1 // Copyright 2013 the V8 project authors. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following
11 // disclaimer in the documentation and/or other materials provided
12 // with the distribution.
13 // * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived
15 // from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #if V8_TARGET_ARCH_ARM64
30
31 #include "src/arm64/assembler-arm64.h"
32
33 #include "src/arm64/assembler-arm64-inl.h"
34 #include "src/base/bits.h"
35 #include "src/base/cpu.h"
36 #include "src/code-stubs.h"
37 #include "src/frame-constants.h"
38 #include "src/register-configuration.h"
39
40 namespace v8 {
41 namespace internal {
42
43 // -----------------------------------------------------------------------------
44 // CpuFeatures implementation.
45
ProbeImpl(bool cross_compile)46 void CpuFeatures::ProbeImpl(bool cross_compile) {
47 // AArch64 has no configuration options, no further probing is required.
48 supported_ = 0;
49
50 // Only use statically determined features for cross compile (snapshot).
51 if (cross_compile) return;
52
53 // We used to probe for coherent cache support, but on older CPUs it
54 // causes crashes (crbug.com/524337), and newer CPUs don't even have
55 // the feature any more.
56 }
57
PrintTarget()58 void CpuFeatures::PrintTarget() { }
PrintFeatures()59 void CpuFeatures::PrintFeatures() {}
60
61 // -----------------------------------------------------------------------------
62 // CPURegList utilities.
63
PopLowestIndex()64 CPURegister CPURegList::PopLowestIndex() {
65 DCHECK(IsValid());
66 if (IsEmpty()) {
67 return NoCPUReg;
68 }
69 int index = CountTrailingZeros(list_, kRegListSizeInBits);
70 DCHECK((1 << index) & list_);
71 Remove(index);
72 return CPURegister::Create(index, size_, type_);
73 }
74
75
PopHighestIndex()76 CPURegister CPURegList::PopHighestIndex() {
77 DCHECK(IsValid());
78 if (IsEmpty()) {
79 return NoCPUReg;
80 }
81 int index = CountLeadingZeros(list_, kRegListSizeInBits);
82 index = kRegListSizeInBits - 1 - index;
83 DCHECK((1 << index) & list_);
84 Remove(index);
85 return CPURegister::Create(index, size_, type_);
86 }
87
88
RemoveCalleeSaved()89 void CPURegList::RemoveCalleeSaved() {
90 if (type() == CPURegister::kRegister) {
91 Remove(GetCalleeSaved(RegisterSizeInBits()));
92 } else if (type() == CPURegister::kVRegister) {
93 Remove(GetCalleeSavedV(RegisterSizeInBits()));
94 } else {
95 DCHECK_EQ(type(), CPURegister::kNoRegister);
96 DCHECK(IsEmpty());
97 // The list must already be empty, so do nothing.
98 }
99 }
100
101
GetCalleeSaved(int size)102 CPURegList CPURegList::GetCalleeSaved(int size) {
103 return CPURegList(CPURegister::kRegister, size, 19, 29);
104 }
105
GetCalleeSavedV(int size)106 CPURegList CPURegList::GetCalleeSavedV(int size) {
107 return CPURegList(CPURegister::kVRegister, size, 8, 15);
108 }
109
110
GetCallerSaved(int size)111 CPURegList CPURegList::GetCallerSaved(int size) {
112 // Registers x0-x18 and lr (x30) are caller-saved.
113 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18);
114 list.Combine(lr);
115 return list;
116 }
117
GetCallerSavedV(int size)118 CPURegList CPURegList::GetCallerSavedV(int size) {
119 // Registers d0-d7 and d16-d31 are caller-saved.
120 CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7);
121 list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31));
122 return list;
123 }
124
125
126 // This function defines the list of registers which are associated with a
127 // safepoint slot. Safepoint register slots are saved contiguously on the stack.
128 // MacroAssembler::SafepointRegisterStackIndex handles mapping from register
129 // code to index in the safepoint register slots. Any change here can affect
130 // this mapping.
GetSafepointSavedRegisters()131 CPURegList CPURegList::GetSafepointSavedRegisters() {
132 CPURegList list = CPURegList::GetCalleeSaved();
133 list.Combine(
134 CPURegList(CPURegister::kRegister, kXRegSizeInBits, kJSCallerSaved));
135
136 // Note that unfortunately we can't use symbolic names for registers and have
137 // to directly use register codes. This is because this function is used to
138 // initialize some static variables and we can't rely on register variables
139 // to be initialized due to static initialization order issues in C++.
140
141 // Drop ip0 and ip1 (i.e. x16 and x17), as they should not be expected to be
142 // preserved outside of the macro assembler.
143 list.Remove(16);
144 list.Remove(17);
145
146 // Add x18 to the safepoint list, as although it's not in kJSCallerSaved, it
147 // is a caller-saved register according to the procedure call standard.
148 list.Combine(18);
149
150 // Add the link register (x30) to the safepoint list.
151 list.Combine(30);
152
153 return list;
154 }
155
156
157 // -----------------------------------------------------------------------------
158 // Implementation of RelocInfo
159
160 const int RelocInfo::kApplyMask =
161 RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
162 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
163 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
164
IsCodedSpecially()165 bool RelocInfo::IsCodedSpecially() {
166 // The deserializer needs to know whether a pointer is specially coded. Being
167 // specially coded on ARM64 means that it is an immediate branch.
168 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
169 if (instr->IsLdrLiteralX()) {
170 return false;
171 } else {
172 DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
173 return true;
174 }
175 }
176
177
IsInConstantPool()178 bool RelocInfo::IsInConstantPool() {
179 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
180 return instr->IsLdrLiteralX();
181 }
182
GetDeoptimizationId(Isolate * isolate,DeoptimizeKind kind)183 int RelocInfo::GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind) {
184 DCHECK(IsRuntimeEntry(rmode_));
185 Instruction* movz_instr = reinterpret_cast<Instruction*>(pc_)->preceding();
186 DCHECK(movz_instr->IsMovz());
187 uint64_t imm = static_cast<uint64_t>(movz_instr->ImmMoveWide())
188 << (16 * movz_instr->ShiftMoveWide());
189 DCHECK_LE(imm, INT_MAX);
190
191 return static_cast<int>(imm);
192 }
193
set_js_to_wasm_address(Address address,ICacheFlushMode icache_flush_mode)194 void RelocInfo::set_js_to_wasm_address(Address address,
195 ICacheFlushMode icache_flush_mode) {
196 DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
197 Assembler::set_target_address_at(pc_, constant_pool_, address,
198 icache_flush_mode);
199 }
200
js_to_wasm_address() const201 Address RelocInfo::js_to_wasm_address() const {
202 DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
203 return Assembler::target_address_at(pc_, constant_pool_);
204 }
205
wasm_call_tag() const206 uint32_t RelocInfo::wasm_call_tag() const {
207 DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
208 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
209 if (instr->IsLdrLiteralX()) {
210 return static_cast<uint32_t>(
211 Memory<Address>(Assembler::target_pointer_address_at(pc_)));
212 } else {
213 DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
214 return static_cast<uint32_t>(instr->ImmPCOffset() / kInstrSize);
215 }
216 }
217
AreAliased(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)218 bool AreAliased(const CPURegister& reg1, const CPURegister& reg2,
219 const CPURegister& reg3, const CPURegister& reg4,
220 const CPURegister& reg5, const CPURegister& reg6,
221 const CPURegister& reg7, const CPURegister& reg8) {
222 int number_of_valid_regs = 0;
223 int number_of_valid_fpregs = 0;
224
225 RegList unique_regs = 0;
226 RegList unique_fpregs = 0;
227
228 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
229
230 for (unsigned i = 0; i < arraysize(regs); i++) {
231 if (regs[i].IsRegister()) {
232 number_of_valid_regs++;
233 unique_regs |= regs[i].bit();
234 } else if (regs[i].IsVRegister()) {
235 number_of_valid_fpregs++;
236 unique_fpregs |= regs[i].bit();
237 } else {
238 DCHECK(!regs[i].IsValid());
239 }
240 }
241
242 int number_of_unique_regs =
243 CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte);
244 int number_of_unique_fpregs =
245 CountSetBits(unique_fpregs, sizeof(unique_fpregs) * kBitsPerByte);
246
247 DCHECK(number_of_valid_regs >= number_of_unique_regs);
248 DCHECK(number_of_valid_fpregs >= number_of_unique_fpregs);
249
250 return (number_of_valid_regs != number_of_unique_regs) ||
251 (number_of_valid_fpregs != number_of_unique_fpregs);
252 }
253
254
AreSameSizeAndType(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)255 bool AreSameSizeAndType(const CPURegister& reg1, const CPURegister& reg2,
256 const CPURegister& reg3, const CPURegister& reg4,
257 const CPURegister& reg5, const CPURegister& reg6,
258 const CPURegister& reg7, const CPURegister& reg8) {
259 DCHECK(reg1.IsValid());
260 bool match = true;
261 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
262 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
263 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
264 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
265 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
266 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
267 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
268 return match;
269 }
270
AreSameFormat(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)271 bool AreSameFormat(const VRegister& reg1, const VRegister& reg2,
272 const VRegister& reg3, const VRegister& reg4) {
273 DCHECK(reg1.IsValid());
274 return (!reg2.IsValid() || reg2.IsSameFormat(reg1)) &&
275 (!reg3.IsValid() || reg3.IsSameFormat(reg1)) &&
276 (!reg4.IsValid() || reg4.IsSameFormat(reg1));
277 }
278
AreConsecutive(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)279 bool AreConsecutive(const VRegister& reg1, const VRegister& reg2,
280 const VRegister& reg3, const VRegister& reg4) {
281 DCHECK(reg1.IsValid());
282 if (!reg2.IsValid()) {
283 DCHECK(!reg3.IsValid() && !reg4.IsValid());
284 return true;
285 } else if (reg2.code() != ((reg1.code() + 1) % kNumberOfVRegisters)) {
286 return false;
287 }
288
289 if (!reg3.IsValid()) {
290 DCHECK(!reg4.IsValid());
291 return true;
292 } else if (reg3.code() != ((reg2.code() + 1) % kNumberOfVRegisters)) {
293 return false;
294 }
295
296 if (!reg4.IsValid()) {
297 return true;
298 } else if (reg4.code() != ((reg3.code() + 1) % kNumberOfVRegisters)) {
299 return false;
300 }
301
302 return true;
303 }
304
InitializeHandle(Handle<HeapObject> handle)305 void Immediate::InitializeHandle(Handle<HeapObject> handle) {
306 value_ = static_cast<intptr_t>(handle.address());
307 rmode_ = RelocInfo::EMBEDDED_OBJECT;
308 }
309
310
NeedsRelocation(const Assembler * assembler) const311 bool Operand::NeedsRelocation(const Assembler* assembler) const {
312 RelocInfo::Mode rmode = immediate_.rmode();
313
314 if (RelocInfo::IsOnlyForSerializer(rmode)) {
315 return assembler->options().record_reloc_info_for_serialization;
316 }
317
318 return !RelocInfo::IsNone(rmode);
319 }
320
AddSharedEntry(SharedEntryMap & entry_map,uint64_t data,int offset)321 bool ConstPool::AddSharedEntry(SharedEntryMap& entry_map, uint64_t data,
322 int offset) {
323 auto existing = entry_map.find(data);
324 if (existing == entry_map.end()) {
325 entry_map[data] = static_cast<int>(entries_.size());
326 entries_.push_back(std::make_pair(data, std::vector<int>(1, offset)));
327 return true;
328 }
329 int index = existing->second;
330 entries_[index].second.push_back(offset);
331 return false;
332 }
333
334 // Constant Pool.
RecordEntry(intptr_t data,RelocInfo::Mode mode)335 bool ConstPool::RecordEntry(intptr_t data, RelocInfo::Mode mode) {
336 DCHECK(mode != RelocInfo::COMMENT && mode != RelocInfo::CONST_POOL &&
337 mode != RelocInfo::VENEER_POOL &&
338 mode != RelocInfo::DEOPT_SCRIPT_OFFSET &&
339 mode != RelocInfo::DEOPT_INLINING_ID &&
340 mode != RelocInfo::DEOPT_REASON && mode != RelocInfo::DEOPT_ID);
341
342 bool write_reloc_info = true;
343
344 uint64_t raw_data = static_cast<uint64_t>(data);
345 int offset = assm_->pc_offset();
346 if (IsEmpty()) {
347 first_use_ = offset;
348 }
349
350 if (RelocInfo::IsShareableRelocMode(mode)) {
351 write_reloc_info = AddSharedEntry(shared_entries_, raw_data, offset);
352 } else if (mode == RelocInfo::CODE_TARGET && raw_data != 0) {
353 // A zero data value is a placeholder and must not be shared.
354 write_reloc_info = AddSharedEntry(handle_to_index_map_, raw_data, offset);
355 } else {
356 entries_.push_back(std::make_pair(raw_data, std::vector<int>(1, offset)));
357 }
358
359 if (EntryCount() > Assembler::kApproxMaxPoolEntryCount) {
360 // Request constant pool emission after the next instruction.
361 assm_->SetNextConstPoolCheckIn(1);
362 }
363
364 return write_reloc_info;
365 }
366
367
DistanceToFirstUse()368 int ConstPool::DistanceToFirstUse() {
369 DCHECK_GE(first_use_, 0);
370 return assm_->pc_offset() - first_use_;
371 }
372
373
MaxPcOffset()374 int ConstPool::MaxPcOffset() {
375 // There are no pending entries in the pool so we can never get out of
376 // range.
377 if (IsEmpty()) return kMaxInt;
378
379 // Entries are not necessarily emitted in the order they are added so in the
380 // worst case the first constant pool use will be accessing the last entry.
381 return first_use_ + kMaxLoadLiteralRange - WorstCaseSize();
382 }
383
384
WorstCaseSize()385 int ConstPool::WorstCaseSize() {
386 if (IsEmpty()) return 0;
387
388 // Max size prologue:
389 // b over
390 // ldr xzr, #pool_size
391 // blr xzr
392 // nop
393 // All entries are 64-bit for now.
394 return 4 * kInstrSize + EntryCount() * kPointerSize;
395 }
396
397
SizeIfEmittedAtCurrentPc(bool require_jump)398 int ConstPool::SizeIfEmittedAtCurrentPc(bool require_jump) {
399 if (IsEmpty()) return 0;
400
401 // Prologue is:
402 // b over ;; if require_jump
403 // ldr xzr, #pool_size
404 // blr xzr
405 // nop ;; if not 64-bit aligned
406 int prologue_size = require_jump ? kInstrSize : 0;
407 prologue_size += 2 * kInstrSize;
408 prologue_size +=
409 IsAligned(assm_->pc_offset() + prologue_size, 8) ? 0 : kInstrSize;
410
411 // All entries are 64-bit for now.
412 return prologue_size + EntryCount() * kPointerSize;
413 }
414
415
Emit(bool require_jump)416 void ConstPool::Emit(bool require_jump) {
417 DCHECK(!assm_->is_const_pool_blocked());
418 // Prevent recursive pool emission and protect from veneer pools.
419 Assembler::BlockPoolsScope block_pools(assm_);
420
421 int size = SizeIfEmittedAtCurrentPc(require_jump);
422 Label size_check;
423 assm_->bind(&size_check);
424
425 assm_->RecordConstPool(size);
426 // Emit the constant pool. It is preceded by an optional branch if
427 // require_jump and a header which will:
428 // 1) Encode the size of the constant pool, for use by the disassembler.
429 // 2) Terminate the program, to try to prevent execution from accidentally
430 // flowing into the constant pool.
431 // 3) align the pool entries to 64-bit.
432 // The header is therefore made of up to three arm64 instructions:
433 // ldr xzr, #<size of the constant pool in 32-bit words>
434 // blr xzr
435 // nop
436 //
437 // If executed, the header will likely segfault and lr will point to the
438 // instruction following the offending blr.
439 // TODO(all): Make the alignment part less fragile. Currently code is
440 // allocated as a byte array so there are no guarantees the alignment will
441 // be preserved on compaction. Currently it works as allocation seems to be
442 // 64-bit aligned.
443
444 // Emit branch if required
445 Label after_pool;
446 if (require_jump) {
447 assm_->b(&after_pool);
448 }
449
450 // Emit the header.
451 assm_->RecordComment("[ Constant Pool");
452 EmitMarker();
453 EmitGuard();
454 assm_->Align(8);
455
456 // Emit constant pool entries.
457 // TODO(all): currently each relocated constant is 64 bits, consider adding
458 // support for 32-bit entries.
459 EmitEntries();
460 assm_->RecordComment("]");
461
462 if (after_pool.is_linked()) {
463 assm_->bind(&after_pool);
464 }
465
466 DCHECK(assm_->SizeOfCodeGeneratedSince(&size_check) ==
467 static_cast<unsigned>(size));
468 }
469
470
Clear()471 void ConstPool::Clear() {
472 shared_entries_.clear();
473 handle_to_index_map_.clear();
474 entries_.clear();
475 first_use_ = -1;
476 }
477
478
EmitMarker()479 void ConstPool::EmitMarker() {
480 // A constant pool size is expressed in number of 32-bits words.
481 // Currently all entries are 64-bit.
482 // + 1 is for the crash guard.
483 // + 0/1 for alignment.
484 int word_count = EntryCount() * 2 + 1 +
485 (IsAligned(assm_->pc_offset(), 8) ? 0 : 1);
486 assm_->Emit(LDR_x_lit |
487 Assembler::ImmLLiteral(word_count) |
488 Assembler::Rt(xzr));
489 }
490
491
AreConsistentForPair(const MemOperand & operandA,const MemOperand & operandB,int access_size_log2)492 MemOperand::PairResult MemOperand::AreConsistentForPair(
493 const MemOperand& operandA,
494 const MemOperand& operandB,
495 int access_size_log2) {
496 DCHECK_GE(access_size_log2, 0);
497 DCHECK_LE(access_size_log2, 3);
498 // Step one: check that they share the same base, that the mode is Offset
499 // and that the offset is a multiple of access size.
500 if (!operandA.base().Is(operandB.base()) ||
501 (operandA.addrmode() != Offset) ||
502 (operandB.addrmode() != Offset) ||
503 ((operandA.offset() & ((1 << access_size_log2) - 1)) != 0)) {
504 return kNotPair;
505 }
506 // Step two: check that the offsets are contiguous and that the range
507 // is OK for ldp/stp.
508 if ((operandB.offset() == operandA.offset() + (1 << access_size_log2)) &&
509 is_int7(operandA.offset() >> access_size_log2)) {
510 return kPairAB;
511 }
512 if ((operandA.offset() == operandB.offset() + (1 << access_size_log2)) &&
513 is_int7(operandB.offset() >> access_size_log2)) {
514 return kPairBA;
515 }
516 return kNotPair;
517 }
518
519
EmitGuard()520 void ConstPool::EmitGuard() {
521 #ifdef DEBUG
522 Instruction* instr = reinterpret_cast<Instruction*>(assm_->pc());
523 DCHECK(instr->preceding()->IsLdrLiteralX() &&
524 instr->preceding()->Rt() == xzr.code());
525 #endif
526 assm_->EmitPoolGuard();
527 }
528
529
EmitEntries()530 void ConstPool::EmitEntries() {
531 DCHECK(IsAligned(assm_->pc_offset(), 8));
532
533 // Emit entries.
534 for (const auto& entry : entries_) {
535 for (const auto& pc : entry.second) {
536 Instruction* instr = assm_->InstructionAt(pc);
537
538 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
539 DCHECK(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
540 instr->SetImmPCOffsetTarget(assm_->options(), assm_->pc());
541 }
542
543 assm_->dc64(entry.first);
544 }
545 Clear();
546 }
547
548
549 // Assembler
Assembler(const AssemblerOptions & options,void * buffer,int buffer_size)550 Assembler::Assembler(const AssemblerOptions& options, void* buffer,
551 int buffer_size)
552 : AssemblerBase(options, buffer, buffer_size),
553 constpool_(this),
554 unresolved_branches_() {
555 const_pool_blocked_nesting_ = 0;
556 veneer_pool_blocked_nesting_ = 0;
557 Reset();
558 }
559
560
~Assembler()561 Assembler::~Assembler() {
562 DCHECK(constpool_.IsEmpty());
563 DCHECK_EQ(const_pool_blocked_nesting_, 0);
564 DCHECK_EQ(veneer_pool_blocked_nesting_, 0);
565 }
566
567
Reset()568 void Assembler::Reset() {
569 #ifdef DEBUG
570 DCHECK((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_));
571 DCHECK_EQ(const_pool_blocked_nesting_, 0);
572 DCHECK_EQ(veneer_pool_blocked_nesting_, 0);
573 DCHECK(unresolved_branches_.empty());
574 memset(buffer_, 0, pc_ - buffer_);
575 #endif
576 pc_ = buffer_;
577 ReserveCodeTargetSpace(64);
578 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
579 constpool_.Clear();
580 next_constant_pool_check_ = 0;
581 next_veneer_pool_check_ = kMaxInt;
582 no_const_pool_before_ = 0;
583 }
584
AllocateAndInstallRequestedHeapObjects(Isolate * isolate)585 void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
586 for (auto& request : heap_object_requests_) {
587 Address pc = reinterpret_cast<Address>(buffer_) + request.offset();
588 switch (request.kind()) {
589 case HeapObjectRequest::kHeapNumber: {
590 Handle<HeapObject> object =
591 isolate->factory()->NewHeapNumber(request.heap_number(), TENURED);
592 set_target_address_at(pc, 0 /* unused */, object.address());
593 break;
594 }
595 case HeapObjectRequest::kCodeStub: {
596 request.code_stub()->set_isolate(isolate);
597 Instruction* instr = reinterpret_cast<Instruction*>(pc);
598 DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
599 DCHECK_EQ(instr->ImmPCOffset() % kInstrSize, 0);
600 UpdateCodeTarget(instr->ImmPCOffset() >> kInstrSizeLog2,
601 request.code_stub()->GetCode());
602 break;
603 }
604 }
605 }
606 }
607
GetCode(Isolate * isolate,CodeDesc * desc)608 void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
609 // Emit constant pool if necessary.
610 CheckConstPool(true, false);
611 DCHECK(constpool_.IsEmpty());
612
613 AllocateAndInstallRequestedHeapObjects(isolate);
614
615 // Set up code descriptor.
616 if (desc) {
617 desc->buffer = reinterpret_cast<byte*>(buffer_);
618 desc->buffer_size = buffer_size_;
619 desc->instr_size = pc_offset();
620 desc->reloc_size =
621 static_cast<int>((reinterpret_cast<byte*>(buffer_) + buffer_size_) -
622 reloc_info_writer.pos());
623 desc->origin = this;
624 desc->constant_pool_size = 0;
625 desc->unwinding_info_size = 0;
626 desc->unwinding_info = nullptr;
627 }
628 }
629
630
Align(int m)631 void Assembler::Align(int m) {
632 DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
633 while ((pc_offset() & (m - 1)) != 0) {
634 nop();
635 }
636 }
637
638
CheckLabelLinkChain(Label const * label)639 void Assembler::CheckLabelLinkChain(Label const * label) {
640 #ifdef DEBUG
641 if (label->is_linked()) {
642 static const int kMaxLinksToCheck = 64; // Avoid O(n2) behaviour.
643 int links_checked = 0;
644 int64_t linkoffset = label->pos();
645 bool end_of_chain = false;
646 while (!end_of_chain) {
647 if (++links_checked > kMaxLinksToCheck) break;
648 Instruction * link = InstructionAt(linkoffset);
649 int64_t linkpcoffset = link->ImmPCOffset();
650 int64_t prevlinkoffset = linkoffset + linkpcoffset;
651
652 end_of_chain = (linkoffset == prevlinkoffset);
653 linkoffset = linkoffset + linkpcoffset;
654 }
655 }
656 #endif
657 }
658
659
RemoveBranchFromLabelLinkChain(Instruction * branch,Label * label,Instruction * label_veneer)660 void Assembler::RemoveBranchFromLabelLinkChain(Instruction* branch,
661 Label* label,
662 Instruction* label_veneer) {
663 DCHECK(label->is_linked());
664
665 CheckLabelLinkChain(label);
666
667 Instruction* link = InstructionAt(label->pos());
668 Instruction* prev_link = link;
669 Instruction* next_link;
670 bool end_of_chain = false;
671
672 while (link != branch && !end_of_chain) {
673 next_link = link->ImmPCOffsetTarget();
674 end_of_chain = (link == next_link);
675 prev_link = link;
676 link = next_link;
677 }
678
679 DCHECK(branch == link);
680 next_link = branch->ImmPCOffsetTarget();
681
682 if (branch == prev_link) {
683 // The branch is the first instruction in the chain.
684 if (branch == next_link) {
685 // It is also the last instruction in the chain, so it is the only branch
686 // currently referring to this label.
687 label->Unuse();
688 } else {
689 label->link_to(
690 static_cast<int>(reinterpret_cast<byte*>(next_link) - buffer_));
691 }
692
693 } else if (branch == next_link) {
694 // The branch is the last (but not also the first) instruction in the chain.
695 prev_link->SetImmPCOffsetTarget(options(), prev_link);
696
697 } else {
698 // The branch is in the middle of the chain.
699 if (prev_link->IsTargetInImmPCOffsetRange(next_link)) {
700 prev_link->SetImmPCOffsetTarget(options(), next_link);
701 } else if (label_veneer != nullptr) {
702 // Use the veneer for all previous links in the chain.
703 prev_link->SetImmPCOffsetTarget(options(), prev_link);
704
705 end_of_chain = false;
706 link = next_link;
707 while (!end_of_chain) {
708 next_link = link->ImmPCOffsetTarget();
709 end_of_chain = (link == next_link);
710 link->SetImmPCOffsetTarget(options(), label_veneer);
711 link = next_link;
712 }
713 } else {
714 // The assert below will fire.
715 // Some other work could be attempted to fix up the chain, but it would be
716 // rather complicated. If we crash here, we may want to consider using an
717 // other mechanism than a chain of branches.
718 //
719 // Note that this situation currently should not happen, as we always call
720 // this function with a veneer to the target label.
721 // However this could happen with a MacroAssembler in the following state:
722 // [previous code]
723 // B(label);
724 // [20KB code]
725 // Tbz(label); // First tbz. Pointing to unconditional branch.
726 // [20KB code]
727 // Tbz(label); // Second tbz. Pointing to the first tbz.
728 // [more code]
729 // and this function is called to remove the first tbz from the label link
730 // chain. Since tbz has a range of +-32KB, the second tbz cannot point to
731 // the unconditional branch.
732 CHECK(prev_link->IsTargetInImmPCOffsetRange(next_link));
733 UNREACHABLE();
734 }
735 }
736
737 CheckLabelLinkChain(label);
738 }
739
740
bind(Label * label)741 void Assembler::bind(Label* label) {
742 // Bind label to the address at pc_. All instructions (most likely branches)
743 // that are linked to this label will be updated to point to the newly-bound
744 // label.
745
746 DCHECK(!label->is_near_linked());
747 DCHECK(!label->is_bound());
748
749 DeleteUnresolvedBranchInfoForLabel(label);
750
751 // If the label is linked, the link chain looks something like this:
752 //
753 // |--I----I-------I-------L
754 // |---------------------->| pc_offset
755 // |-------------->| linkoffset = label->pos()
756 // |<------| link->ImmPCOffset()
757 // |------>| prevlinkoffset = linkoffset + link->ImmPCOffset()
758 //
759 // On each iteration, the last link is updated and then removed from the
760 // chain until only one remains. At that point, the label is bound.
761 //
762 // If the label is not linked, no preparation is required before binding.
763 while (label->is_linked()) {
764 int linkoffset = label->pos();
765 Instruction* link = InstructionAt(linkoffset);
766 int prevlinkoffset = linkoffset + static_cast<int>(link->ImmPCOffset());
767
768 CheckLabelLinkChain(label);
769
770 DCHECK_GE(linkoffset, 0);
771 DCHECK(linkoffset < pc_offset());
772 DCHECK((linkoffset > prevlinkoffset) ||
773 (linkoffset - prevlinkoffset == kStartOfLabelLinkChain));
774 DCHECK_GE(prevlinkoffset, 0);
775
776 // Update the link to point to the label.
777 if (link->IsUnresolvedInternalReference()) {
778 // Internal references do not get patched to an instruction but directly
779 // to an address.
780 internal_reference_positions_.push_back(linkoffset);
781 PatchingAssembler patcher(options(), reinterpret_cast<byte*>(link), 2);
782 patcher.dc64(reinterpret_cast<uintptr_t>(pc_));
783 } else {
784 link->SetImmPCOffsetTarget(options(),
785 reinterpret_cast<Instruction*>(pc_));
786 }
787
788 // Link the label to the previous link in the chain.
789 if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) {
790 // We hit kStartOfLabelLinkChain, so the chain is fully processed.
791 label->Unuse();
792 } else {
793 // Update the label for the next iteration.
794 label->link_to(prevlinkoffset);
795 }
796 }
797 label->bind_to(pc_offset());
798
799 DCHECK(label->is_bound());
800 DCHECK(!label->is_linked());
801 }
802
803
LinkAndGetByteOffsetTo(Label * label)804 int Assembler::LinkAndGetByteOffsetTo(Label* label) {
805 DCHECK_EQ(sizeof(*pc_), 1);
806 CheckLabelLinkChain(label);
807
808 int offset;
809 if (label->is_bound()) {
810 // The label is bound, so it does not need to be updated. Referring
811 // instructions must link directly to the label as they will not be
812 // updated.
813 //
814 // In this case, label->pos() returns the offset of the label from the
815 // start of the buffer.
816 //
817 // Note that offset can be zero for self-referential instructions. (This
818 // could be useful for ADR, for example.)
819 offset = label->pos() - pc_offset();
820 DCHECK_LE(offset, 0);
821 } else {
822 if (label->is_linked()) {
823 // The label is linked, so the referring instruction should be added onto
824 // the end of the label's link chain.
825 //
826 // In this case, label->pos() returns the offset of the last linked
827 // instruction from the start of the buffer.
828 offset = label->pos() - pc_offset();
829 DCHECK_NE(offset, kStartOfLabelLinkChain);
830 // Note that the offset here needs to be PC-relative only so that the
831 // first instruction in a buffer can link to an unbound label. Otherwise,
832 // the offset would be 0 for this case, and 0 is reserved for
833 // kStartOfLabelLinkChain.
834 } else {
835 // The label is unused, so it now becomes linked and the referring
836 // instruction is at the start of the new link chain.
837 offset = kStartOfLabelLinkChain;
838 }
839 // The instruction at pc is now the last link in the label's chain.
840 label->link_to(pc_offset());
841 }
842
843 return offset;
844 }
845
846
DeleteUnresolvedBranchInfoForLabelTraverse(Label * label)847 void Assembler::DeleteUnresolvedBranchInfoForLabelTraverse(Label* label) {
848 DCHECK(label->is_linked());
849 CheckLabelLinkChain(label);
850
851 int link_offset = label->pos();
852 int link_pcoffset;
853 bool end_of_chain = false;
854
855 while (!end_of_chain) {
856 Instruction * link = InstructionAt(link_offset);
857 link_pcoffset = static_cast<int>(link->ImmPCOffset());
858
859 // ADR instructions are not handled by veneers.
860 if (link->IsImmBranch()) {
861 int max_reachable_pc =
862 static_cast<int>(InstructionOffset(link) +
863 Instruction::ImmBranchRange(link->BranchType()));
864 typedef std::multimap<int, FarBranchInfo>::iterator unresolved_info_it;
865 std::pair<unresolved_info_it, unresolved_info_it> range;
866 range = unresolved_branches_.equal_range(max_reachable_pc);
867 unresolved_info_it it;
868 for (it = range.first; it != range.second; ++it) {
869 if (it->second.pc_offset_ == link_offset) {
870 unresolved_branches_.erase(it);
871 break;
872 }
873 }
874 }
875
876 end_of_chain = (link_pcoffset == 0);
877 link_offset = link_offset + link_pcoffset;
878 }
879 }
880
881
DeleteUnresolvedBranchInfoForLabel(Label * label)882 void Assembler::DeleteUnresolvedBranchInfoForLabel(Label* label) {
883 if (unresolved_branches_.empty()) {
884 DCHECK_EQ(next_veneer_pool_check_, kMaxInt);
885 return;
886 }
887
888 if (label->is_linked()) {
889 // Branches to this label will be resolved when the label is bound, normally
890 // just after all the associated info has been deleted.
891 DeleteUnresolvedBranchInfoForLabelTraverse(label);
892 }
893 if (unresolved_branches_.empty()) {
894 next_veneer_pool_check_ = kMaxInt;
895 } else {
896 next_veneer_pool_check_ =
897 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
898 }
899 }
900
901
StartBlockConstPool()902 void Assembler::StartBlockConstPool() {
903 if (const_pool_blocked_nesting_++ == 0) {
904 // Prevent constant pool checks happening by setting the next check to
905 // the biggest possible offset.
906 next_constant_pool_check_ = kMaxInt;
907 }
908 }
909
910
EndBlockConstPool()911 void Assembler::EndBlockConstPool() {
912 if (--const_pool_blocked_nesting_ == 0) {
913 // Check the constant pool hasn't been blocked for too long.
914 DCHECK(pc_offset() < constpool_.MaxPcOffset());
915 // Two cases:
916 // * no_const_pool_before_ >= next_constant_pool_check_ and the emission is
917 // still blocked
918 // * no_const_pool_before_ < next_constant_pool_check_ and the next emit
919 // will trigger a check.
920 next_constant_pool_check_ = no_const_pool_before_;
921 }
922 }
923
924
is_const_pool_blocked() const925 bool Assembler::is_const_pool_blocked() const {
926 return (const_pool_blocked_nesting_ > 0) ||
927 (pc_offset() < no_const_pool_before_);
928 }
929
930
IsConstantPoolAt(Instruction * instr)931 bool Assembler::IsConstantPoolAt(Instruction* instr) {
932 // The constant pool marker is made of two instructions. These instructions
933 // will never be emitted by the JIT, so checking for the first one is enough:
934 // 0: ldr xzr, #<size of pool>
935 bool result = instr->IsLdrLiteralX() && (instr->Rt() == kZeroRegCode);
936
937 // It is still worth asserting the marker is complete.
938 // 4: blr xzr
939 DCHECK(!result || (instr->following()->IsBranchAndLinkToRegister() &&
940 instr->following()->Rn() == kZeroRegCode));
941
942 return result;
943 }
944
945
ConstantPoolSizeAt(Instruction * instr)946 int Assembler::ConstantPoolSizeAt(Instruction* instr) {
947 #ifdef USE_SIMULATOR
948 // Assembler::debug() embeds constants directly into the instruction stream.
949 // Although this is not a genuine constant pool, treat it like one to avoid
950 // disassembling the constants.
951 if ((instr->Mask(ExceptionMask) == HLT) &&
952 (instr->ImmException() == kImmExceptionIsDebug)) {
953 const char* message =
954 reinterpret_cast<const char*>(
955 instr->InstructionAtOffset(kDebugMessageOffset));
956 int size = static_cast<int>(kDebugMessageOffset + strlen(message) + 1);
957 return RoundUp(size, kInstrSize) / kInstrSize;
958 }
959 // Same for printf support, see MacroAssembler::CallPrintf().
960 if ((instr->Mask(ExceptionMask) == HLT) &&
961 (instr->ImmException() == kImmExceptionIsPrintf)) {
962 return kPrintfLength / kInstrSize;
963 }
964 #endif
965 if (IsConstantPoolAt(instr)) {
966 return instr->ImmLLiteral();
967 } else {
968 return -1;
969 }
970 }
971
972
EmitPoolGuard()973 void Assembler::EmitPoolGuard() {
974 // We must generate only one instruction as this is used in scopes that
975 // control the size of the code generated.
976 Emit(BLR | Rn(xzr));
977 }
978
979
StartBlockVeneerPool()980 void Assembler::StartBlockVeneerPool() {
981 ++veneer_pool_blocked_nesting_;
982 }
983
984
EndBlockVeneerPool()985 void Assembler::EndBlockVeneerPool() {
986 if (--veneer_pool_blocked_nesting_ == 0) {
987 // Check the veneer pool hasn't been blocked for too long.
988 DCHECK(unresolved_branches_.empty() ||
989 (pc_offset() < unresolved_branches_first_limit()));
990 }
991 }
992
993
br(const Register & xn)994 void Assembler::br(const Register& xn) {
995 DCHECK(xn.Is64Bits());
996 Emit(BR | Rn(xn));
997 }
998
999
blr(const Register & xn)1000 void Assembler::blr(const Register& xn) {
1001 DCHECK(xn.Is64Bits());
1002 // The pattern 'blr xzr' is used as a guard to detect when execution falls
1003 // through the constant pool. It should not be emitted.
1004 DCHECK(!xn.Is(xzr));
1005 Emit(BLR | Rn(xn));
1006 }
1007
1008
ret(const Register & xn)1009 void Assembler::ret(const Register& xn) {
1010 DCHECK(xn.Is64Bits());
1011 Emit(RET | Rn(xn));
1012 }
1013
1014
b(int imm26)1015 void Assembler::b(int imm26) {
1016 Emit(B | ImmUncondBranch(imm26));
1017 }
1018
1019
b(Label * label)1020 void Assembler::b(Label* label) {
1021 b(LinkAndGetInstructionOffsetTo(label));
1022 }
1023
1024
b(int imm19,Condition cond)1025 void Assembler::b(int imm19, Condition cond) {
1026 Emit(B_cond | ImmCondBranch(imm19) | cond);
1027 }
1028
1029
b(Label * label,Condition cond)1030 void Assembler::b(Label* label, Condition cond) {
1031 b(LinkAndGetInstructionOffsetTo(label), cond);
1032 }
1033
1034
bl(int imm26)1035 void Assembler::bl(int imm26) {
1036 Emit(BL | ImmUncondBranch(imm26));
1037 }
1038
1039
bl(Label * label)1040 void Assembler::bl(Label* label) {
1041 bl(LinkAndGetInstructionOffsetTo(label));
1042 }
1043
1044
cbz(const Register & rt,int imm19)1045 void Assembler::cbz(const Register& rt,
1046 int imm19) {
1047 Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));
1048 }
1049
1050
cbz(const Register & rt,Label * label)1051 void Assembler::cbz(const Register& rt,
1052 Label* label) {
1053 cbz(rt, LinkAndGetInstructionOffsetTo(label));
1054 }
1055
1056
cbnz(const Register & rt,int imm19)1057 void Assembler::cbnz(const Register& rt,
1058 int imm19) {
1059 Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));
1060 }
1061
1062
cbnz(const Register & rt,Label * label)1063 void Assembler::cbnz(const Register& rt,
1064 Label* label) {
1065 cbnz(rt, LinkAndGetInstructionOffsetTo(label));
1066 }
1067
1068
tbz(const Register & rt,unsigned bit_pos,int imm14)1069 void Assembler::tbz(const Register& rt,
1070 unsigned bit_pos,
1071 int imm14) {
1072 DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
1073 Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
1074 }
1075
1076
tbz(const Register & rt,unsigned bit_pos,Label * label)1077 void Assembler::tbz(const Register& rt,
1078 unsigned bit_pos,
1079 Label* label) {
1080 tbz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
1081 }
1082
1083
tbnz(const Register & rt,unsigned bit_pos,int imm14)1084 void Assembler::tbnz(const Register& rt,
1085 unsigned bit_pos,
1086 int imm14) {
1087 DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
1088 Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
1089 }
1090
1091
tbnz(const Register & rt,unsigned bit_pos,Label * label)1092 void Assembler::tbnz(const Register& rt,
1093 unsigned bit_pos,
1094 Label* label) {
1095 tbnz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
1096 }
1097
1098
adr(const Register & rd,int imm21)1099 void Assembler::adr(const Register& rd, int imm21) {
1100 DCHECK(rd.Is64Bits());
1101 Emit(ADR | ImmPCRelAddress(imm21) | Rd(rd));
1102 }
1103
1104
adr(const Register & rd,Label * label)1105 void Assembler::adr(const Register& rd, Label* label) {
1106 adr(rd, LinkAndGetByteOffsetTo(label));
1107 }
1108
1109
add(const Register & rd,const Register & rn,const Operand & operand)1110 void Assembler::add(const Register& rd,
1111 const Register& rn,
1112 const Operand& operand) {
1113 AddSub(rd, rn, operand, LeaveFlags, ADD);
1114 }
1115
1116
adds(const Register & rd,const Register & rn,const Operand & operand)1117 void Assembler::adds(const Register& rd,
1118 const Register& rn,
1119 const Operand& operand) {
1120 AddSub(rd, rn, operand, SetFlags, ADD);
1121 }
1122
1123
cmn(const Register & rn,const Operand & operand)1124 void Assembler::cmn(const Register& rn,
1125 const Operand& operand) {
1126 Register zr = AppropriateZeroRegFor(rn);
1127 adds(zr, rn, operand);
1128 }
1129
1130
sub(const Register & rd,const Register & rn,const Operand & operand)1131 void Assembler::sub(const Register& rd,
1132 const Register& rn,
1133 const Operand& operand) {
1134 AddSub(rd, rn, operand, LeaveFlags, SUB);
1135 }
1136
1137
subs(const Register & rd,const Register & rn,const Operand & operand)1138 void Assembler::subs(const Register& rd,
1139 const Register& rn,
1140 const Operand& operand) {
1141 AddSub(rd, rn, operand, SetFlags, SUB);
1142 }
1143
1144
cmp(const Register & rn,const Operand & operand)1145 void Assembler::cmp(const Register& rn, const Operand& operand) {
1146 Register zr = AppropriateZeroRegFor(rn);
1147 subs(zr, rn, operand);
1148 }
1149
1150
neg(const Register & rd,const Operand & operand)1151 void Assembler::neg(const Register& rd, const Operand& operand) {
1152 Register zr = AppropriateZeroRegFor(rd);
1153 sub(rd, zr, operand);
1154 }
1155
1156
negs(const Register & rd,const Operand & operand)1157 void Assembler::negs(const Register& rd, const Operand& operand) {
1158 Register zr = AppropriateZeroRegFor(rd);
1159 subs(rd, zr, operand);
1160 }
1161
1162
adc(const Register & rd,const Register & rn,const Operand & operand)1163 void Assembler::adc(const Register& rd,
1164 const Register& rn,
1165 const Operand& operand) {
1166 AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);
1167 }
1168
1169
adcs(const Register & rd,const Register & rn,const Operand & operand)1170 void Assembler::adcs(const Register& rd,
1171 const Register& rn,
1172 const Operand& operand) {
1173 AddSubWithCarry(rd, rn, operand, SetFlags, ADC);
1174 }
1175
1176
sbc(const Register & rd,const Register & rn,const Operand & operand)1177 void Assembler::sbc(const Register& rd,
1178 const Register& rn,
1179 const Operand& operand) {
1180 AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);
1181 }
1182
1183
sbcs(const Register & rd,const Register & rn,const Operand & operand)1184 void Assembler::sbcs(const Register& rd,
1185 const Register& rn,
1186 const Operand& operand) {
1187 AddSubWithCarry(rd, rn, operand, SetFlags, SBC);
1188 }
1189
1190
ngc(const Register & rd,const Operand & operand)1191 void Assembler::ngc(const Register& rd, const Operand& operand) {
1192 Register zr = AppropriateZeroRegFor(rd);
1193 sbc(rd, zr, operand);
1194 }
1195
1196
ngcs(const Register & rd,const Operand & operand)1197 void Assembler::ngcs(const Register& rd, const Operand& operand) {
1198 Register zr = AppropriateZeroRegFor(rd);
1199 sbcs(rd, zr, operand);
1200 }
1201
1202
1203 // Logical instructions.
and_(const Register & rd,const Register & rn,const Operand & operand)1204 void Assembler::and_(const Register& rd,
1205 const Register& rn,
1206 const Operand& operand) {
1207 Logical(rd, rn, operand, AND);
1208 }
1209
1210
ands(const Register & rd,const Register & rn,const Operand & operand)1211 void Assembler::ands(const Register& rd,
1212 const Register& rn,
1213 const Operand& operand) {
1214 Logical(rd, rn, operand, ANDS);
1215 }
1216
1217
tst(const Register & rn,const Operand & operand)1218 void Assembler::tst(const Register& rn,
1219 const Operand& operand) {
1220 ands(AppropriateZeroRegFor(rn), rn, operand);
1221 }
1222
1223
bic(const Register & rd,const Register & rn,const Operand & operand)1224 void Assembler::bic(const Register& rd,
1225 const Register& rn,
1226 const Operand& operand) {
1227 Logical(rd, rn, operand, BIC);
1228 }
1229
1230
bics(const Register & rd,const Register & rn,const Operand & operand)1231 void Assembler::bics(const Register& rd,
1232 const Register& rn,
1233 const Operand& operand) {
1234 Logical(rd, rn, operand, BICS);
1235 }
1236
1237
orr(const Register & rd,const Register & rn,const Operand & operand)1238 void Assembler::orr(const Register& rd,
1239 const Register& rn,
1240 const Operand& operand) {
1241 Logical(rd, rn, operand, ORR);
1242 }
1243
1244
orn(const Register & rd,const Register & rn,const Operand & operand)1245 void Assembler::orn(const Register& rd,
1246 const Register& rn,
1247 const Operand& operand) {
1248 Logical(rd, rn, operand, ORN);
1249 }
1250
1251
eor(const Register & rd,const Register & rn,const Operand & operand)1252 void Assembler::eor(const Register& rd,
1253 const Register& rn,
1254 const Operand& operand) {
1255 Logical(rd, rn, operand, EOR);
1256 }
1257
1258
eon(const Register & rd,const Register & rn,const Operand & operand)1259 void Assembler::eon(const Register& rd,
1260 const Register& rn,
1261 const Operand& operand) {
1262 Logical(rd, rn, operand, EON);
1263 }
1264
1265
lslv(const Register & rd,const Register & rn,const Register & rm)1266 void Assembler::lslv(const Register& rd,
1267 const Register& rn,
1268 const Register& rm) {
1269 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1270 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1271 Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));
1272 }
1273
1274
lsrv(const Register & rd,const Register & rn,const Register & rm)1275 void Assembler::lsrv(const Register& rd,
1276 const Register& rn,
1277 const Register& rm) {
1278 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1279 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1280 Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));
1281 }
1282
1283
asrv(const Register & rd,const Register & rn,const Register & rm)1284 void Assembler::asrv(const Register& rd,
1285 const Register& rn,
1286 const Register& rm) {
1287 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1288 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1289 Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));
1290 }
1291
1292
rorv(const Register & rd,const Register & rn,const Register & rm)1293 void Assembler::rorv(const Register& rd,
1294 const Register& rn,
1295 const Register& rm) {
1296 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1297 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1298 Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));
1299 }
1300
1301
1302 // Bitfield operations.
bfm(const Register & rd,const Register & rn,int immr,int imms)1303 void Assembler::bfm(const Register& rd, const Register& rn, int immr,
1304 int imms) {
1305 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1306 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1307 Emit(SF(rd) | BFM | N |
1308 ImmR(immr, rd.SizeInBits()) |
1309 ImmS(imms, rn.SizeInBits()) |
1310 Rn(rn) | Rd(rd));
1311 }
1312
1313
sbfm(const Register & rd,const Register & rn,int immr,int imms)1314 void Assembler::sbfm(const Register& rd, const Register& rn, int immr,
1315 int imms) {
1316 DCHECK(rd.Is64Bits() || rn.Is32Bits());
1317 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1318 Emit(SF(rd) | SBFM | N |
1319 ImmR(immr, rd.SizeInBits()) |
1320 ImmS(imms, rn.SizeInBits()) |
1321 Rn(rn) | Rd(rd));
1322 }
1323
1324
ubfm(const Register & rd,const Register & rn,int immr,int imms)1325 void Assembler::ubfm(const Register& rd, const Register& rn, int immr,
1326 int imms) {
1327 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1328 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1329 Emit(SF(rd) | UBFM | N |
1330 ImmR(immr, rd.SizeInBits()) |
1331 ImmS(imms, rn.SizeInBits()) |
1332 Rn(rn) | Rd(rd));
1333 }
1334
1335
extr(const Register & rd,const Register & rn,const Register & rm,int lsb)1336 void Assembler::extr(const Register& rd, const Register& rn, const Register& rm,
1337 int lsb) {
1338 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1339 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1340 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1341 Emit(SF(rd) | EXTR | N | Rm(rm) |
1342 ImmS(lsb, rn.SizeInBits()) | Rn(rn) | Rd(rd));
1343 }
1344
1345
csel(const Register & rd,const Register & rn,const Register & rm,Condition cond)1346 void Assembler::csel(const Register& rd,
1347 const Register& rn,
1348 const Register& rm,
1349 Condition cond) {
1350 ConditionalSelect(rd, rn, rm, cond, CSEL);
1351 }
1352
1353
csinc(const Register & rd,const Register & rn,const Register & rm,Condition cond)1354 void Assembler::csinc(const Register& rd,
1355 const Register& rn,
1356 const Register& rm,
1357 Condition cond) {
1358 ConditionalSelect(rd, rn, rm, cond, CSINC);
1359 }
1360
1361
csinv(const Register & rd,const Register & rn,const Register & rm,Condition cond)1362 void Assembler::csinv(const Register& rd,
1363 const Register& rn,
1364 const Register& rm,
1365 Condition cond) {
1366 ConditionalSelect(rd, rn, rm, cond, CSINV);
1367 }
1368
1369
csneg(const Register & rd,const Register & rn,const Register & rm,Condition cond)1370 void Assembler::csneg(const Register& rd,
1371 const Register& rn,
1372 const Register& rm,
1373 Condition cond) {
1374 ConditionalSelect(rd, rn, rm, cond, CSNEG);
1375 }
1376
1377
cset(const Register & rd,Condition cond)1378 void Assembler::cset(const Register &rd, Condition cond) {
1379 DCHECK((cond != al) && (cond != nv));
1380 Register zr = AppropriateZeroRegFor(rd);
1381 csinc(rd, zr, zr, NegateCondition(cond));
1382 }
1383
1384
csetm(const Register & rd,Condition cond)1385 void Assembler::csetm(const Register &rd, Condition cond) {
1386 DCHECK((cond != al) && (cond != nv));
1387 Register zr = AppropriateZeroRegFor(rd);
1388 csinv(rd, zr, zr, NegateCondition(cond));
1389 }
1390
1391
cinc(const Register & rd,const Register & rn,Condition cond)1392 void Assembler::cinc(const Register &rd, const Register &rn, Condition cond) {
1393 DCHECK((cond != al) && (cond != nv));
1394 csinc(rd, rn, rn, NegateCondition(cond));
1395 }
1396
1397
cinv(const Register & rd,const Register & rn,Condition cond)1398 void Assembler::cinv(const Register &rd, const Register &rn, Condition cond) {
1399 DCHECK((cond != al) && (cond != nv));
1400 csinv(rd, rn, rn, NegateCondition(cond));
1401 }
1402
1403
cneg(const Register & rd,const Register & rn,Condition cond)1404 void Assembler::cneg(const Register &rd, const Register &rn, Condition cond) {
1405 DCHECK((cond != al) && (cond != nv));
1406 csneg(rd, rn, rn, NegateCondition(cond));
1407 }
1408
1409
ConditionalSelect(const Register & rd,const Register & rn,const Register & rm,Condition cond,ConditionalSelectOp op)1410 void Assembler::ConditionalSelect(const Register& rd,
1411 const Register& rn,
1412 const Register& rm,
1413 Condition cond,
1414 ConditionalSelectOp op) {
1415 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1416 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1417 Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));
1418 }
1419
1420
ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1421 void Assembler::ccmn(const Register& rn,
1422 const Operand& operand,
1423 StatusFlags nzcv,
1424 Condition cond) {
1425 ConditionalCompare(rn, operand, nzcv, cond, CCMN);
1426 }
1427
1428
ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1429 void Assembler::ccmp(const Register& rn,
1430 const Operand& operand,
1431 StatusFlags nzcv,
1432 Condition cond) {
1433 ConditionalCompare(rn, operand, nzcv, cond, CCMP);
1434 }
1435
1436
DataProcessing3Source(const Register & rd,const Register & rn,const Register & rm,const Register & ra,DataProcessing3SourceOp op)1437 void Assembler::DataProcessing3Source(const Register& rd,
1438 const Register& rn,
1439 const Register& rm,
1440 const Register& ra,
1441 DataProcessing3SourceOp op) {
1442 Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));
1443 }
1444
1445
mul(const Register & rd,const Register & rn,const Register & rm)1446 void Assembler::mul(const Register& rd,
1447 const Register& rn,
1448 const Register& rm) {
1449 DCHECK(AreSameSizeAndType(rd, rn, rm));
1450 Register zr = AppropriateZeroRegFor(rn);
1451 DataProcessing3Source(rd, rn, rm, zr, MADD);
1452 }
1453
1454
madd(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1455 void Assembler::madd(const Register& rd,
1456 const Register& rn,
1457 const Register& rm,
1458 const Register& ra) {
1459 DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
1460 DataProcessing3Source(rd, rn, rm, ra, MADD);
1461 }
1462
1463
mneg(const Register & rd,const Register & rn,const Register & rm)1464 void Assembler::mneg(const Register& rd,
1465 const Register& rn,
1466 const Register& rm) {
1467 DCHECK(AreSameSizeAndType(rd, rn, rm));
1468 Register zr = AppropriateZeroRegFor(rn);
1469 DataProcessing3Source(rd, rn, rm, zr, MSUB);
1470 }
1471
1472
msub(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1473 void Assembler::msub(const Register& rd,
1474 const Register& rn,
1475 const Register& rm,
1476 const Register& ra) {
1477 DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
1478 DataProcessing3Source(rd, rn, rm, ra, MSUB);
1479 }
1480
1481
smaddl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1482 void Assembler::smaddl(const Register& rd,
1483 const Register& rn,
1484 const Register& rm,
1485 const Register& ra) {
1486 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1487 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1488 DataProcessing3Source(rd, rn, rm, ra, SMADDL_x);
1489 }
1490
1491
smsubl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1492 void Assembler::smsubl(const Register& rd,
1493 const Register& rn,
1494 const Register& rm,
1495 const Register& ra) {
1496 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1497 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1498 DataProcessing3Source(rd, rn, rm, ra, SMSUBL_x);
1499 }
1500
1501
umaddl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1502 void Assembler::umaddl(const Register& rd,
1503 const Register& rn,
1504 const Register& rm,
1505 const Register& ra) {
1506 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1507 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1508 DataProcessing3Source(rd, rn, rm, ra, UMADDL_x);
1509 }
1510
1511
umsubl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1512 void Assembler::umsubl(const Register& rd,
1513 const Register& rn,
1514 const Register& rm,
1515 const Register& ra) {
1516 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1517 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1518 DataProcessing3Source(rd, rn, rm, ra, UMSUBL_x);
1519 }
1520
1521
smull(const Register & rd,const Register & rn,const Register & rm)1522 void Assembler::smull(const Register& rd,
1523 const Register& rn,
1524 const Register& rm) {
1525 DCHECK(rd.Is64Bits());
1526 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1527 DataProcessing3Source(rd, rn, rm, xzr, SMADDL_x);
1528 }
1529
1530
smulh(const Register & rd,const Register & rn,const Register & rm)1531 void Assembler::smulh(const Register& rd,
1532 const Register& rn,
1533 const Register& rm) {
1534 DCHECK(AreSameSizeAndType(rd, rn, rm));
1535 DataProcessing3Source(rd, rn, rm, xzr, SMULH_x);
1536 }
1537
1538
sdiv(const Register & rd,const Register & rn,const Register & rm)1539 void Assembler::sdiv(const Register& rd,
1540 const Register& rn,
1541 const Register& rm) {
1542 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1543 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1544 Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));
1545 }
1546
1547
udiv(const Register & rd,const Register & rn,const Register & rm)1548 void Assembler::udiv(const Register& rd,
1549 const Register& rn,
1550 const Register& rm) {
1551 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1552 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1553 Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));
1554 }
1555
1556
rbit(const Register & rd,const Register & rn)1557 void Assembler::rbit(const Register& rd,
1558 const Register& rn) {
1559 DataProcessing1Source(rd, rn, RBIT);
1560 }
1561
1562
rev16(const Register & rd,const Register & rn)1563 void Assembler::rev16(const Register& rd,
1564 const Register& rn) {
1565 DataProcessing1Source(rd, rn, REV16);
1566 }
1567
1568
rev32(const Register & rd,const Register & rn)1569 void Assembler::rev32(const Register& rd,
1570 const Register& rn) {
1571 DCHECK(rd.Is64Bits());
1572 DataProcessing1Source(rd, rn, REV);
1573 }
1574
1575
rev(const Register & rd,const Register & rn)1576 void Assembler::rev(const Register& rd,
1577 const Register& rn) {
1578 DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);
1579 }
1580
1581
clz(const Register & rd,const Register & rn)1582 void Assembler::clz(const Register& rd,
1583 const Register& rn) {
1584 DataProcessing1Source(rd, rn, CLZ);
1585 }
1586
1587
cls(const Register & rd,const Register & rn)1588 void Assembler::cls(const Register& rd,
1589 const Register& rn) {
1590 DataProcessing1Source(rd, rn, CLS);
1591 }
1592
1593
ldp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & src)1594 void Assembler::ldp(const CPURegister& rt,
1595 const CPURegister& rt2,
1596 const MemOperand& src) {
1597 LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
1598 }
1599
1600
stp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & dst)1601 void Assembler::stp(const CPURegister& rt,
1602 const CPURegister& rt2,
1603 const MemOperand& dst) {
1604 LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
1605 }
1606
1607
ldpsw(const Register & rt,const Register & rt2,const MemOperand & src)1608 void Assembler::ldpsw(const Register& rt,
1609 const Register& rt2,
1610 const MemOperand& src) {
1611 DCHECK(rt.Is64Bits());
1612 LoadStorePair(rt, rt2, src, LDPSW_x);
1613 }
1614
1615
LoadStorePair(const CPURegister & rt,const CPURegister & rt2,const MemOperand & addr,LoadStorePairOp op)1616 void Assembler::LoadStorePair(const CPURegister& rt,
1617 const CPURegister& rt2,
1618 const MemOperand& addr,
1619 LoadStorePairOp op) {
1620 // 'rt' and 'rt2' can only be aliased for stores.
1621 DCHECK(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));
1622 DCHECK(AreSameSizeAndType(rt, rt2));
1623 DCHECK(IsImmLSPair(addr.offset(), CalcLSPairDataSize(op)));
1624 int offset = static_cast<int>(addr.offset());
1625
1626 Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
1627 ImmLSPair(offset, CalcLSPairDataSize(op));
1628
1629 Instr addrmodeop;
1630 if (addr.IsImmediateOffset()) {
1631 addrmodeop = LoadStorePairOffsetFixed;
1632 } else {
1633 // Pre-index and post-index modes.
1634 DCHECK(!rt.Is(addr.base()));
1635 DCHECK(!rt2.Is(addr.base()));
1636 DCHECK_NE(addr.offset(), 0);
1637 if (addr.IsPreIndex()) {
1638 addrmodeop = LoadStorePairPreIndexFixed;
1639 } else {
1640 DCHECK(addr.IsPostIndex());
1641 addrmodeop = LoadStorePairPostIndexFixed;
1642 }
1643 }
1644 Emit(addrmodeop | memop);
1645 }
1646
1647
1648 // Memory instructions.
ldrb(const Register & rt,const MemOperand & src)1649 void Assembler::ldrb(const Register& rt, const MemOperand& src) {
1650 LoadStore(rt, src, LDRB_w);
1651 }
1652
1653
strb(const Register & rt,const MemOperand & dst)1654 void Assembler::strb(const Register& rt, const MemOperand& dst) {
1655 LoadStore(rt, dst, STRB_w);
1656 }
1657
1658
ldrsb(const Register & rt,const MemOperand & src)1659 void Assembler::ldrsb(const Register& rt, const MemOperand& src) {
1660 LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w);
1661 }
1662
1663
ldrh(const Register & rt,const MemOperand & src)1664 void Assembler::ldrh(const Register& rt, const MemOperand& src) {
1665 LoadStore(rt, src, LDRH_w);
1666 }
1667
1668
strh(const Register & rt,const MemOperand & dst)1669 void Assembler::strh(const Register& rt, const MemOperand& dst) {
1670 LoadStore(rt, dst, STRH_w);
1671 }
1672
1673
ldrsh(const Register & rt,const MemOperand & src)1674 void Assembler::ldrsh(const Register& rt, const MemOperand& src) {
1675 LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w);
1676 }
1677
1678
ldr(const CPURegister & rt,const MemOperand & src)1679 void Assembler::ldr(const CPURegister& rt, const MemOperand& src) {
1680 LoadStore(rt, src, LoadOpFor(rt));
1681 }
1682
1683
str(const CPURegister & rt,const MemOperand & src)1684 void Assembler::str(const CPURegister& rt, const MemOperand& src) {
1685 LoadStore(rt, src, StoreOpFor(rt));
1686 }
1687
1688
ldrsw(const Register & rt,const MemOperand & src)1689 void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
1690 DCHECK(rt.Is64Bits());
1691 LoadStore(rt, src, LDRSW_x);
1692 }
1693
1694
ldr_pcrel(const CPURegister & rt,int imm19)1695 void Assembler::ldr_pcrel(const CPURegister& rt, int imm19) {
1696 // The pattern 'ldr xzr, #offset' is used to indicate the beginning of a
1697 // constant pool. It should not be emitted.
1698 DCHECK(!rt.IsZero());
1699 Emit(LoadLiteralOpFor(rt) | ImmLLiteral(imm19) | Rt(rt));
1700 }
1701
EmbeddedNumber(double number)1702 Operand Operand::EmbeddedNumber(double number) {
1703 int32_t smi;
1704 if (DoubleToSmiInteger(number, &smi)) {
1705 return Operand(Immediate(Smi::FromInt(smi)));
1706 }
1707 Operand result(0, RelocInfo::EMBEDDED_OBJECT);
1708 result.heap_object_request_.emplace(number);
1709 DCHECK(result.IsHeapObjectRequest());
1710 return result;
1711 }
1712
EmbeddedCode(CodeStub * stub)1713 Operand Operand::EmbeddedCode(CodeStub* stub) {
1714 Operand result(0, RelocInfo::CODE_TARGET);
1715 result.heap_object_request_.emplace(stub);
1716 DCHECK(result.IsHeapObjectRequest());
1717 return result;
1718 }
1719
ldr(const CPURegister & rt,const Operand & operand)1720 void Assembler::ldr(const CPURegister& rt, const Operand& operand) {
1721 if (operand.IsHeapObjectRequest()) {
1722 RequestHeapObject(operand.heap_object_request());
1723 ldr(rt, operand.immediate_for_heap_object_request());
1724 } else {
1725 ldr(rt, operand.immediate());
1726 }
1727 }
1728
ldr(const CPURegister & rt,const Immediate & imm)1729 void Assembler::ldr(const CPURegister& rt, const Immediate& imm) {
1730 // Currently we only support 64-bit literals.
1731 DCHECK(rt.Is64Bits());
1732
1733 RecordRelocInfo(imm.rmode(), imm.value());
1734 BlockConstPoolFor(1);
1735 // The load will be patched when the constpool is emitted, patching code
1736 // expect a load literal with offset 0.
1737 ldr_pcrel(rt, 0);
1738 }
1739
ldar(const Register & rt,const Register & rn)1740 void Assembler::ldar(const Register& rt, const Register& rn) {
1741 DCHECK(rn.Is64Bits());
1742 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? LDAR_w : LDAR_x;
1743 Emit(op | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1744 }
1745
ldaxr(const Register & rt,const Register & rn)1746 void Assembler::ldaxr(const Register& rt, const Register& rn) {
1747 DCHECK(rn.Is64Bits());
1748 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? LDAXR_w : LDAXR_x;
1749 Emit(op | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1750 }
1751
stlr(const Register & rt,const Register & rn)1752 void Assembler::stlr(const Register& rt, const Register& rn) {
1753 DCHECK(rn.Is64Bits());
1754 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? STLR_w : STLR_x;
1755 Emit(op | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1756 }
1757
stlxr(const Register & rs,const Register & rt,const Register & rn)1758 void Assembler::stlxr(const Register& rs, const Register& rt,
1759 const Register& rn) {
1760 DCHECK(rn.Is64Bits());
1761 DCHECK(!rs.Is(rt) && !rs.Is(rn));
1762 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? STLXR_w : STLXR_x;
1763 Emit(op | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
1764 }
1765
ldarb(const Register & rt,const Register & rn)1766 void Assembler::ldarb(const Register& rt, const Register& rn) {
1767 DCHECK(rt.Is32Bits());
1768 DCHECK(rn.Is64Bits());
1769 Emit(LDAR_b | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1770 }
1771
ldaxrb(const Register & rt,const Register & rn)1772 void Assembler::ldaxrb(const Register& rt, const Register& rn) {
1773 DCHECK(rt.Is32Bits());
1774 DCHECK(rn.Is64Bits());
1775 Emit(LDAXR_b | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1776 }
1777
stlrb(const Register & rt,const Register & rn)1778 void Assembler::stlrb(const Register& rt, const Register& rn) {
1779 DCHECK(rt.Is32Bits());
1780 DCHECK(rn.Is64Bits());
1781 Emit(STLR_b | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1782 }
1783
stlxrb(const Register & rs,const Register & rt,const Register & rn)1784 void Assembler::stlxrb(const Register& rs, const Register& rt,
1785 const Register& rn) {
1786 DCHECK(rs.Is32Bits());
1787 DCHECK(rt.Is32Bits());
1788 DCHECK(rn.Is64Bits());
1789 DCHECK(!rs.Is(rt) && !rs.Is(rn));
1790 Emit(STLXR_b | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
1791 }
1792
ldarh(const Register & rt,const Register & rn)1793 void Assembler::ldarh(const Register& rt, const Register& rn) {
1794 DCHECK(rt.Is32Bits());
1795 DCHECK(rn.Is64Bits());
1796 Emit(LDAR_h | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1797 }
1798
ldaxrh(const Register & rt,const Register & rn)1799 void Assembler::ldaxrh(const Register& rt, const Register& rn) {
1800 DCHECK(rt.Is32Bits());
1801 DCHECK(rn.Is64Bits());
1802 Emit(LDAXR_h | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1803 }
1804
stlrh(const Register & rt,const Register & rn)1805 void Assembler::stlrh(const Register& rt, const Register& rn) {
1806 DCHECK(rt.Is32Bits());
1807 DCHECK(rn.Is64Bits());
1808 Emit(STLR_h | Rs(x31) | Rt2(x31) | RnSP(rn) | Rt(rt));
1809 }
1810
stlxrh(const Register & rs,const Register & rt,const Register & rn)1811 void Assembler::stlxrh(const Register& rs, const Register& rt,
1812 const Register& rn) {
1813 DCHECK(rs.Is32Bits());
1814 DCHECK(rt.Is32Bits());
1815 DCHECK(rn.Is64Bits());
1816 DCHECK(!rs.Is(rt) && !rs.Is(rn));
1817 Emit(STLXR_h | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
1818 }
1819
NEON3DifferentL(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)1820 void Assembler::NEON3DifferentL(const VRegister& vd, const VRegister& vn,
1821 const VRegister& vm, NEON3DifferentOp vop) {
1822 DCHECK(AreSameFormat(vn, vm));
1823 DCHECK((vn.Is1H() && vd.Is1S()) || (vn.Is1S() && vd.Is1D()) ||
1824 (vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||
1825 (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||
1826 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
1827 Instr format, op = vop;
1828 if (vd.IsScalar()) {
1829 op |= NEON_Q | NEONScalar;
1830 format = SFormat(vn);
1831 } else {
1832 format = VFormat(vn);
1833 }
1834 Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
1835 }
1836
NEON3DifferentW(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)1837 void Assembler::NEON3DifferentW(const VRegister& vd, const VRegister& vn,
1838 const VRegister& vm, NEON3DifferentOp vop) {
1839 DCHECK(AreSameFormat(vd, vn));
1840 DCHECK((vm.Is8B() && vd.Is8H()) || (vm.Is4H() && vd.Is4S()) ||
1841 (vm.Is2S() && vd.Is2D()) || (vm.Is16B() && vd.Is8H()) ||
1842 (vm.Is8H() && vd.Is4S()) || (vm.Is4S() && vd.Is2D()));
1843 Emit(VFormat(vm) | vop | Rm(vm) | Rn(vn) | Rd(vd));
1844 }
1845
NEON3DifferentHN(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3DifferentOp vop)1846 void Assembler::NEON3DifferentHN(const VRegister& vd, const VRegister& vn,
1847 const VRegister& vm, NEON3DifferentOp vop) {
1848 DCHECK(AreSameFormat(vm, vn));
1849 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
1850 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
1851 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
1852 Emit(VFormat(vd) | vop | Rm(vm) | Rn(vn) | Rd(vd));
1853 }
1854
1855 #define NEON_3DIFF_LONG_LIST(V) \
1856 V(pmull, NEON_PMULL, vn.IsVector() && vn.Is8B()) \
1857 V(pmull2, NEON_PMULL2, vn.IsVector() && vn.Is16B()) \
1858 V(saddl, NEON_SADDL, vn.IsVector() && vn.IsD()) \
1859 V(saddl2, NEON_SADDL2, vn.IsVector() && vn.IsQ()) \
1860 V(sabal, NEON_SABAL, vn.IsVector() && vn.IsD()) \
1861 V(sabal2, NEON_SABAL2, vn.IsVector() && vn.IsQ()) \
1862 V(uabal, NEON_UABAL, vn.IsVector() && vn.IsD()) \
1863 V(uabal2, NEON_UABAL2, vn.IsVector() && vn.IsQ()) \
1864 V(sabdl, NEON_SABDL, vn.IsVector() && vn.IsD()) \
1865 V(sabdl2, NEON_SABDL2, vn.IsVector() && vn.IsQ()) \
1866 V(uabdl, NEON_UABDL, vn.IsVector() && vn.IsD()) \
1867 V(uabdl2, NEON_UABDL2, vn.IsVector() && vn.IsQ()) \
1868 V(smlal, NEON_SMLAL, vn.IsVector() && vn.IsD()) \
1869 V(smlal2, NEON_SMLAL2, vn.IsVector() && vn.IsQ()) \
1870 V(umlal, NEON_UMLAL, vn.IsVector() && vn.IsD()) \
1871 V(umlal2, NEON_UMLAL2, vn.IsVector() && vn.IsQ()) \
1872 V(smlsl, NEON_SMLSL, vn.IsVector() && vn.IsD()) \
1873 V(smlsl2, NEON_SMLSL2, vn.IsVector() && vn.IsQ()) \
1874 V(umlsl, NEON_UMLSL, vn.IsVector() && vn.IsD()) \
1875 V(umlsl2, NEON_UMLSL2, vn.IsVector() && vn.IsQ()) \
1876 V(smull, NEON_SMULL, vn.IsVector() && vn.IsD()) \
1877 V(smull2, NEON_SMULL2, vn.IsVector() && vn.IsQ()) \
1878 V(umull, NEON_UMULL, vn.IsVector() && vn.IsD()) \
1879 V(umull2, NEON_UMULL2, vn.IsVector() && vn.IsQ()) \
1880 V(ssubl, NEON_SSUBL, vn.IsVector() && vn.IsD()) \
1881 V(ssubl2, NEON_SSUBL2, vn.IsVector() && vn.IsQ()) \
1882 V(uaddl, NEON_UADDL, vn.IsVector() && vn.IsD()) \
1883 V(uaddl2, NEON_UADDL2, vn.IsVector() && vn.IsQ()) \
1884 V(usubl, NEON_USUBL, vn.IsVector() && vn.IsD()) \
1885 V(usubl2, NEON_USUBL2, vn.IsVector() && vn.IsQ()) \
1886 V(sqdmlal, NEON_SQDMLAL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
1887 V(sqdmlal2, NEON_SQDMLAL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \
1888 V(sqdmlsl, NEON_SQDMLSL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
1889 V(sqdmlsl2, NEON_SQDMLSL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \
1890 V(sqdmull, NEON_SQDMULL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \
1891 V(sqdmull2, NEON_SQDMULL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S())
1892
1893 #define DEFINE_ASM_FUNC(FN, OP, AS) \
1894 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
1895 const VRegister& vm) { \
1896 DCHECK(AS); \
1897 NEON3DifferentL(vd, vn, vm, OP); \
1898 }
1899 NEON_3DIFF_LONG_LIST(DEFINE_ASM_FUNC)
1900 #undef DEFINE_ASM_FUNC
1901
1902 #define NEON_3DIFF_HN_LIST(V) \
1903 V(addhn, NEON_ADDHN, vd.IsD()) \
1904 V(addhn2, NEON_ADDHN2, vd.IsQ()) \
1905 V(raddhn, NEON_RADDHN, vd.IsD()) \
1906 V(raddhn2, NEON_RADDHN2, vd.IsQ()) \
1907 V(subhn, NEON_SUBHN, vd.IsD()) \
1908 V(subhn2, NEON_SUBHN2, vd.IsQ()) \
1909 V(rsubhn, NEON_RSUBHN, vd.IsD()) \
1910 V(rsubhn2, NEON_RSUBHN2, vd.IsQ())
1911
1912 #define DEFINE_ASM_FUNC(FN, OP, AS) \
1913 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
1914 const VRegister& vm) { \
1915 DCHECK(AS); \
1916 NEON3DifferentHN(vd, vn, vm, OP); \
1917 }
NEON_3DIFF_HN_LIST(DEFINE_ASM_FUNC)1918 NEON_3DIFF_HN_LIST(DEFINE_ASM_FUNC)
1919 #undef DEFINE_ASM_FUNC
1920
1921 void Assembler::NEONPerm(const VRegister& vd, const VRegister& vn,
1922 const VRegister& vm, NEONPermOp op) {
1923 DCHECK(AreSameFormat(vd, vn, vm));
1924 DCHECK(!vd.Is1D());
1925 Emit(VFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
1926 }
1927
trn1(const VRegister & vd,const VRegister & vn,const VRegister & vm)1928 void Assembler::trn1(const VRegister& vd, const VRegister& vn,
1929 const VRegister& vm) {
1930 NEONPerm(vd, vn, vm, NEON_TRN1);
1931 }
1932
trn2(const VRegister & vd,const VRegister & vn,const VRegister & vm)1933 void Assembler::trn2(const VRegister& vd, const VRegister& vn,
1934 const VRegister& vm) {
1935 NEONPerm(vd, vn, vm, NEON_TRN2);
1936 }
1937
uzp1(const VRegister & vd,const VRegister & vn,const VRegister & vm)1938 void Assembler::uzp1(const VRegister& vd, const VRegister& vn,
1939 const VRegister& vm) {
1940 NEONPerm(vd, vn, vm, NEON_UZP1);
1941 }
1942
uzp2(const VRegister & vd,const VRegister & vn,const VRegister & vm)1943 void Assembler::uzp2(const VRegister& vd, const VRegister& vn,
1944 const VRegister& vm) {
1945 NEONPerm(vd, vn, vm, NEON_UZP2);
1946 }
1947
zip1(const VRegister & vd,const VRegister & vn,const VRegister & vm)1948 void Assembler::zip1(const VRegister& vd, const VRegister& vn,
1949 const VRegister& vm) {
1950 NEONPerm(vd, vn, vm, NEON_ZIP1);
1951 }
1952
zip2(const VRegister & vd,const VRegister & vn,const VRegister & vm)1953 void Assembler::zip2(const VRegister& vd, const VRegister& vn,
1954 const VRegister& vm) {
1955 NEONPerm(vd, vn, vm, NEON_ZIP2);
1956 }
1957
NEONShiftImmediate(const VRegister & vd,const VRegister & vn,NEONShiftImmediateOp op,int immh_immb)1958 void Assembler::NEONShiftImmediate(const VRegister& vd, const VRegister& vn,
1959 NEONShiftImmediateOp op, int immh_immb) {
1960 DCHECK(AreSameFormat(vd, vn));
1961 Instr q, scalar;
1962 if (vn.IsScalar()) {
1963 q = NEON_Q;
1964 scalar = NEONScalar;
1965 } else {
1966 q = vd.IsD() ? 0 : NEON_Q;
1967 scalar = 0;
1968 }
1969 Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));
1970 }
1971
NEONShiftLeftImmediate(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)1972 void Assembler::NEONShiftLeftImmediate(const VRegister& vd, const VRegister& vn,
1973 int shift, NEONShiftImmediateOp op) {
1974 int laneSizeInBits = vn.LaneSizeInBits();
1975 DCHECK((shift >= 0) && (shift < laneSizeInBits));
1976 NEONShiftImmediate(vd, vn, op, (laneSizeInBits + shift) << 16);
1977 }
1978
NEONShiftRightImmediate(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)1979 void Assembler::NEONShiftRightImmediate(const VRegister& vd,
1980 const VRegister& vn, int shift,
1981 NEONShiftImmediateOp op) {
1982 int laneSizeInBits = vn.LaneSizeInBits();
1983 DCHECK((shift >= 1) && (shift <= laneSizeInBits));
1984 NEONShiftImmediate(vd, vn, op, ((2 * laneSizeInBits) - shift) << 16);
1985 }
1986
NEONShiftImmediateL(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)1987 void Assembler::NEONShiftImmediateL(const VRegister& vd, const VRegister& vn,
1988 int shift, NEONShiftImmediateOp op) {
1989 int laneSizeInBits = vn.LaneSizeInBits();
1990 DCHECK((shift >= 0) && (shift < laneSizeInBits));
1991 int immh_immb = (laneSizeInBits + shift) << 16;
1992
1993 DCHECK((vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||
1994 (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||
1995 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
1996 Instr q;
1997 q = vn.IsD() ? 0 : NEON_Q;
1998 Emit(q | op | immh_immb | Rn(vn) | Rd(vd));
1999 }
2000
NEONShiftImmediateN(const VRegister & vd,const VRegister & vn,int shift,NEONShiftImmediateOp op)2001 void Assembler::NEONShiftImmediateN(const VRegister& vd, const VRegister& vn,
2002 int shift, NEONShiftImmediateOp op) {
2003 Instr q, scalar;
2004 int laneSizeInBits = vd.LaneSizeInBits();
2005 DCHECK((shift >= 1) && (shift <= laneSizeInBits));
2006 int immh_immb = (2 * laneSizeInBits - shift) << 16;
2007
2008 if (vn.IsScalar()) {
2009 DCHECK((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||
2010 (vd.Is1S() && vn.Is1D()));
2011 q = NEON_Q;
2012 scalar = NEONScalar;
2013 } else {
2014 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
2015 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
2016 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
2017 scalar = 0;
2018 q = vd.IsD() ? 0 : NEON_Q;
2019 }
2020 Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));
2021 }
2022
shl(const VRegister & vd,const VRegister & vn,int shift)2023 void Assembler::shl(const VRegister& vd, const VRegister& vn, int shift) {
2024 DCHECK(vd.IsVector() || vd.Is1D());
2025 NEONShiftLeftImmediate(vd, vn, shift, NEON_SHL);
2026 }
2027
sli(const VRegister & vd,const VRegister & vn,int shift)2028 void Assembler::sli(const VRegister& vd, const VRegister& vn, int shift) {
2029 DCHECK(vd.IsVector() || vd.Is1D());
2030 NEONShiftLeftImmediate(vd, vn, shift, NEON_SLI);
2031 }
2032
sqshl(const VRegister & vd,const VRegister & vn,int shift)2033 void Assembler::sqshl(const VRegister& vd, const VRegister& vn, int shift) {
2034 NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHL_imm);
2035 }
2036
sqshlu(const VRegister & vd,const VRegister & vn,int shift)2037 void Assembler::sqshlu(const VRegister& vd, const VRegister& vn, int shift) {
2038 NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHLU);
2039 }
2040
uqshl(const VRegister & vd,const VRegister & vn,int shift)2041 void Assembler::uqshl(const VRegister& vd, const VRegister& vn, int shift) {
2042 NEONShiftLeftImmediate(vd, vn, shift, NEON_UQSHL_imm);
2043 }
2044
sshll(const VRegister & vd,const VRegister & vn,int shift)2045 void Assembler::sshll(const VRegister& vd, const VRegister& vn, int shift) {
2046 DCHECK(vn.IsD());
2047 NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);
2048 }
2049
sshll2(const VRegister & vd,const VRegister & vn,int shift)2050 void Assembler::sshll2(const VRegister& vd, const VRegister& vn, int shift) {
2051 DCHECK(vn.IsQ());
2052 NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);
2053 }
2054
sxtl(const VRegister & vd,const VRegister & vn)2055 void Assembler::sxtl(const VRegister& vd, const VRegister& vn) {
2056 sshll(vd, vn, 0);
2057 }
2058
sxtl2(const VRegister & vd,const VRegister & vn)2059 void Assembler::sxtl2(const VRegister& vd, const VRegister& vn) {
2060 sshll2(vd, vn, 0);
2061 }
2062
ushll(const VRegister & vd,const VRegister & vn,int shift)2063 void Assembler::ushll(const VRegister& vd, const VRegister& vn, int shift) {
2064 DCHECK(vn.IsD());
2065 NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);
2066 }
2067
ushll2(const VRegister & vd,const VRegister & vn,int shift)2068 void Assembler::ushll2(const VRegister& vd, const VRegister& vn, int shift) {
2069 DCHECK(vn.IsQ());
2070 NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);
2071 }
2072
uxtl(const VRegister & vd,const VRegister & vn)2073 void Assembler::uxtl(const VRegister& vd, const VRegister& vn) {
2074 ushll(vd, vn, 0);
2075 }
2076
uxtl2(const VRegister & vd,const VRegister & vn)2077 void Assembler::uxtl2(const VRegister& vd, const VRegister& vn) {
2078 ushll2(vd, vn, 0);
2079 }
2080
sri(const VRegister & vd,const VRegister & vn,int shift)2081 void Assembler::sri(const VRegister& vd, const VRegister& vn, int shift) {
2082 DCHECK(vd.IsVector() || vd.Is1D());
2083 NEONShiftRightImmediate(vd, vn, shift, NEON_SRI);
2084 }
2085
sshr(const VRegister & vd,const VRegister & vn,int shift)2086 void Assembler::sshr(const VRegister& vd, const VRegister& vn, int shift) {
2087 DCHECK(vd.IsVector() || vd.Is1D());
2088 NEONShiftRightImmediate(vd, vn, shift, NEON_SSHR);
2089 }
2090
ushr(const VRegister & vd,const VRegister & vn,int shift)2091 void Assembler::ushr(const VRegister& vd, const VRegister& vn, int shift) {
2092 DCHECK(vd.IsVector() || vd.Is1D());
2093 NEONShiftRightImmediate(vd, vn, shift, NEON_USHR);
2094 }
2095
srshr(const VRegister & vd,const VRegister & vn,int shift)2096 void Assembler::srshr(const VRegister& vd, const VRegister& vn, int shift) {
2097 DCHECK(vd.IsVector() || vd.Is1D());
2098 NEONShiftRightImmediate(vd, vn, shift, NEON_SRSHR);
2099 }
2100
urshr(const VRegister & vd,const VRegister & vn,int shift)2101 void Assembler::urshr(const VRegister& vd, const VRegister& vn, int shift) {
2102 DCHECK(vd.IsVector() || vd.Is1D());
2103 NEONShiftRightImmediate(vd, vn, shift, NEON_URSHR);
2104 }
2105
ssra(const VRegister & vd,const VRegister & vn,int shift)2106 void Assembler::ssra(const VRegister& vd, const VRegister& vn, int shift) {
2107 DCHECK(vd.IsVector() || vd.Is1D());
2108 NEONShiftRightImmediate(vd, vn, shift, NEON_SSRA);
2109 }
2110
usra(const VRegister & vd,const VRegister & vn,int shift)2111 void Assembler::usra(const VRegister& vd, const VRegister& vn, int shift) {
2112 DCHECK(vd.IsVector() || vd.Is1D());
2113 NEONShiftRightImmediate(vd, vn, shift, NEON_USRA);
2114 }
2115
srsra(const VRegister & vd,const VRegister & vn,int shift)2116 void Assembler::srsra(const VRegister& vd, const VRegister& vn, int shift) {
2117 DCHECK(vd.IsVector() || vd.Is1D());
2118 NEONShiftRightImmediate(vd, vn, shift, NEON_SRSRA);
2119 }
2120
ursra(const VRegister & vd,const VRegister & vn,int shift)2121 void Assembler::ursra(const VRegister& vd, const VRegister& vn, int shift) {
2122 DCHECK(vd.IsVector() || vd.Is1D());
2123 NEONShiftRightImmediate(vd, vn, shift, NEON_URSRA);
2124 }
2125
shrn(const VRegister & vd,const VRegister & vn,int shift)2126 void Assembler::shrn(const VRegister& vd, const VRegister& vn, int shift) {
2127 DCHECK(vn.IsVector() && vd.IsD());
2128 NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);
2129 }
2130
shrn2(const VRegister & vd,const VRegister & vn,int shift)2131 void Assembler::shrn2(const VRegister& vd, const VRegister& vn, int shift) {
2132 DCHECK(vn.IsVector() && vd.IsQ());
2133 NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);
2134 }
2135
rshrn(const VRegister & vd,const VRegister & vn,int shift)2136 void Assembler::rshrn(const VRegister& vd, const VRegister& vn, int shift) {
2137 DCHECK(vn.IsVector() && vd.IsD());
2138 NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);
2139 }
2140
rshrn2(const VRegister & vd,const VRegister & vn,int shift)2141 void Assembler::rshrn2(const VRegister& vd, const VRegister& vn, int shift) {
2142 DCHECK(vn.IsVector() && vd.IsQ());
2143 NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);
2144 }
2145
sqshrn(const VRegister & vd,const VRegister & vn,int shift)2146 void Assembler::sqshrn(const VRegister& vd, const VRegister& vn, int shift) {
2147 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2148 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);
2149 }
2150
sqshrn2(const VRegister & vd,const VRegister & vn,int shift)2151 void Assembler::sqshrn2(const VRegister& vd, const VRegister& vn, int shift) {
2152 DCHECK(vn.IsVector() && vd.IsQ());
2153 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);
2154 }
2155
sqrshrn(const VRegister & vd,const VRegister & vn,int shift)2156 void Assembler::sqrshrn(const VRegister& vd, const VRegister& vn, int shift) {
2157 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2158 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);
2159 }
2160
sqrshrn2(const VRegister & vd,const VRegister & vn,int shift)2161 void Assembler::sqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {
2162 DCHECK(vn.IsVector() && vd.IsQ());
2163 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);
2164 }
2165
sqshrun(const VRegister & vd,const VRegister & vn,int shift)2166 void Assembler::sqshrun(const VRegister& vd, const VRegister& vn, int shift) {
2167 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2168 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);
2169 }
2170
sqshrun2(const VRegister & vd,const VRegister & vn,int shift)2171 void Assembler::sqshrun2(const VRegister& vd, const VRegister& vn, int shift) {
2172 DCHECK(vn.IsVector() && vd.IsQ());
2173 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);
2174 }
2175
sqrshrun(const VRegister & vd,const VRegister & vn,int shift)2176 void Assembler::sqrshrun(const VRegister& vd, const VRegister& vn, int shift) {
2177 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2178 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);
2179 }
2180
sqrshrun2(const VRegister & vd,const VRegister & vn,int shift)2181 void Assembler::sqrshrun2(const VRegister& vd, const VRegister& vn, int shift) {
2182 DCHECK(vn.IsVector() && vd.IsQ());
2183 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);
2184 }
2185
uqshrn(const VRegister & vd,const VRegister & vn,int shift)2186 void Assembler::uqshrn(const VRegister& vd, const VRegister& vn, int shift) {
2187 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2188 NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);
2189 }
2190
uqshrn2(const VRegister & vd,const VRegister & vn,int shift)2191 void Assembler::uqshrn2(const VRegister& vd, const VRegister& vn, int shift) {
2192 DCHECK(vn.IsVector() && vd.IsQ());
2193 NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);
2194 }
2195
uqrshrn(const VRegister & vd,const VRegister & vn,int shift)2196 void Assembler::uqrshrn(const VRegister& vd, const VRegister& vn, int shift) {
2197 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));
2198 NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);
2199 }
2200
uqrshrn2(const VRegister & vd,const VRegister & vn,int shift)2201 void Assembler::uqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {
2202 DCHECK(vn.IsVector() && vd.IsQ());
2203 NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);
2204 }
2205
uaddw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2206 void Assembler::uaddw(const VRegister& vd, const VRegister& vn,
2207 const VRegister& vm) {
2208 DCHECK(vm.IsD());
2209 NEON3DifferentW(vd, vn, vm, NEON_UADDW);
2210 }
2211
uaddw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2212 void Assembler::uaddw2(const VRegister& vd, const VRegister& vn,
2213 const VRegister& vm) {
2214 DCHECK(vm.IsQ());
2215 NEON3DifferentW(vd, vn, vm, NEON_UADDW2);
2216 }
2217
saddw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2218 void Assembler::saddw(const VRegister& vd, const VRegister& vn,
2219 const VRegister& vm) {
2220 DCHECK(vm.IsD());
2221 NEON3DifferentW(vd, vn, vm, NEON_SADDW);
2222 }
2223
saddw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2224 void Assembler::saddw2(const VRegister& vd, const VRegister& vn,
2225 const VRegister& vm) {
2226 DCHECK(vm.IsQ());
2227 NEON3DifferentW(vd, vn, vm, NEON_SADDW2);
2228 }
2229
usubw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2230 void Assembler::usubw(const VRegister& vd, const VRegister& vn,
2231 const VRegister& vm) {
2232 DCHECK(vm.IsD());
2233 NEON3DifferentW(vd, vn, vm, NEON_USUBW);
2234 }
2235
usubw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2236 void Assembler::usubw2(const VRegister& vd, const VRegister& vn,
2237 const VRegister& vm) {
2238 DCHECK(vm.IsQ());
2239 NEON3DifferentW(vd, vn, vm, NEON_USUBW2);
2240 }
2241
ssubw(const VRegister & vd,const VRegister & vn,const VRegister & vm)2242 void Assembler::ssubw(const VRegister& vd, const VRegister& vn,
2243 const VRegister& vm) {
2244 DCHECK(vm.IsD());
2245 NEON3DifferentW(vd, vn, vm, NEON_SSUBW);
2246 }
2247
ssubw2(const VRegister & vd,const VRegister & vn,const VRegister & vm)2248 void Assembler::ssubw2(const VRegister& vd, const VRegister& vn,
2249 const VRegister& vm) {
2250 DCHECK(vm.IsQ());
2251 NEON3DifferentW(vd, vn, vm, NEON_SSUBW2);
2252 }
2253
mov(const Register & rd,const Register & rm)2254 void Assembler::mov(const Register& rd, const Register& rm) {
2255 // Moves involving the stack pointer are encoded as add immediate with
2256 // second operand of zero. Otherwise, orr with first operand zr is
2257 // used.
2258 if (rd.IsSP() || rm.IsSP()) {
2259 add(rd, rm, 0);
2260 } else {
2261 orr(rd, AppropriateZeroRegFor(rd), rm);
2262 }
2263 }
2264
ins(const VRegister & vd,int vd_index,const Register & rn)2265 void Assembler::ins(const VRegister& vd, int vd_index, const Register& rn) {
2266 // We support vd arguments of the form vd.VxT() or vd.T(), where x is the
2267 // number of lanes, and T is b, h, s or d.
2268 int lane_size = vd.LaneSizeInBytes();
2269 NEONFormatField format;
2270 switch (lane_size) {
2271 case 1:
2272 format = NEON_16B;
2273 DCHECK(rn.IsW());
2274 break;
2275 case 2:
2276 format = NEON_8H;
2277 DCHECK(rn.IsW());
2278 break;
2279 case 4:
2280 format = NEON_4S;
2281 DCHECK(rn.IsW());
2282 break;
2283 default:
2284 DCHECK_EQ(lane_size, 8);
2285 DCHECK(rn.IsX());
2286 format = NEON_2D;
2287 break;
2288 }
2289
2290 DCHECK((0 <= vd_index) &&
2291 (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
2292 Emit(NEON_INS_GENERAL | ImmNEON5(format, vd_index) | Rn(rn) | Rd(vd));
2293 }
2294
mov(const Register & rd,const VRegister & vn,int vn_index)2295 void Assembler::mov(const Register& rd, const VRegister& vn, int vn_index) {
2296 DCHECK_GE(vn.SizeInBytes(), 4);
2297 umov(rd, vn, vn_index);
2298 }
2299
smov(const Register & rd,const VRegister & vn,int vn_index)2300 void Assembler::smov(const Register& rd, const VRegister& vn, int vn_index) {
2301 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
2302 // number of lanes, and T is b, h, s.
2303 int lane_size = vn.LaneSizeInBytes();
2304 NEONFormatField format;
2305 Instr q = 0;
2306 switch (lane_size) {
2307 case 1:
2308 format = NEON_16B;
2309 break;
2310 case 2:
2311 format = NEON_8H;
2312 break;
2313 default:
2314 DCHECK_EQ(lane_size, 4);
2315 DCHECK(rd.IsX());
2316 format = NEON_4S;
2317 break;
2318 }
2319 q = rd.IsW() ? 0 : NEON_Q;
2320 DCHECK((0 <= vn_index) &&
2321 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
2322 Emit(q | NEON_SMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));
2323 }
2324
cls(const VRegister & vd,const VRegister & vn)2325 void Assembler::cls(const VRegister& vd, const VRegister& vn) {
2326 DCHECK(AreSameFormat(vd, vn));
2327 DCHECK(!vd.Is1D() && !vd.Is2D());
2328 Emit(VFormat(vn) | NEON_CLS | Rn(vn) | Rd(vd));
2329 }
2330
clz(const VRegister & vd,const VRegister & vn)2331 void Assembler::clz(const VRegister& vd, const VRegister& vn) {
2332 DCHECK(AreSameFormat(vd, vn));
2333 DCHECK(!vd.Is1D() && !vd.Is2D());
2334 Emit(VFormat(vn) | NEON_CLZ | Rn(vn) | Rd(vd));
2335 }
2336
cnt(const VRegister & vd,const VRegister & vn)2337 void Assembler::cnt(const VRegister& vd, const VRegister& vn) {
2338 DCHECK(AreSameFormat(vd, vn));
2339 DCHECK(vd.Is8B() || vd.Is16B());
2340 Emit(VFormat(vn) | NEON_CNT | Rn(vn) | Rd(vd));
2341 }
2342
rev16(const VRegister & vd,const VRegister & vn)2343 void Assembler::rev16(const VRegister& vd, const VRegister& vn) {
2344 DCHECK(AreSameFormat(vd, vn));
2345 DCHECK(vd.Is8B() || vd.Is16B());
2346 Emit(VFormat(vn) | NEON_REV16 | Rn(vn) | Rd(vd));
2347 }
2348
rev32(const VRegister & vd,const VRegister & vn)2349 void Assembler::rev32(const VRegister& vd, const VRegister& vn) {
2350 DCHECK(AreSameFormat(vd, vn));
2351 DCHECK(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H());
2352 Emit(VFormat(vn) | NEON_REV32 | Rn(vn) | Rd(vd));
2353 }
2354
rev64(const VRegister & vd,const VRegister & vn)2355 void Assembler::rev64(const VRegister& vd, const VRegister& vn) {
2356 DCHECK(AreSameFormat(vd, vn));
2357 DCHECK(!vd.Is1D() && !vd.Is2D());
2358 Emit(VFormat(vn) | NEON_REV64 | Rn(vn) | Rd(vd));
2359 }
2360
ursqrte(const VRegister & vd,const VRegister & vn)2361 void Assembler::ursqrte(const VRegister& vd, const VRegister& vn) {
2362 DCHECK(AreSameFormat(vd, vn));
2363 DCHECK(vd.Is2S() || vd.Is4S());
2364 Emit(VFormat(vn) | NEON_URSQRTE | Rn(vn) | Rd(vd));
2365 }
2366
urecpe(const VRegister & vd,const VRegister & vn)2367 void Assembler::urecpe(const VRegister& vd, const VRegister& vn) {
2368 DCHECK(AreSameFormat(vd, vn));
2369 DCHECK(vd.Is2S() || vd.Is4S());
2370 Emit(VFormat(vn) | NEON_URECPE | Rn(vn) | Rd(vd));
2371 }
2372
NEONAddlp(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp op)2373 void Assembler::NEONAddlp(const VRegister& vd, const VRegister& vn,
2374 NEON2RegMiscOp op) {
2375 DCHECK((op == NEON_SADDLP) || (op == NEON_UADDLP) || (op == NEON_SADALP) ||
2376 (op == NEON_UADALP));
2377
2378 DCHECK((vn.Is8B() && vd.Is4H()) || (vn.Is4H() && vd.Is2S()) ||
2379 (vn.Is2S() && vd.Is1D()) || (vn.Is16B() && vd.Is8H()) ||
2380 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));
2381 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
2382 }
2383
saddlp(const VRegister & vd,const VRegister & vn)2384 void Assembler::saddlp(const VRegister& vd, const VRegister& vn) {
2385 NEONAddlp(vd, vn, NEON_SADDLP);
2386 }
2387
uaddlp(const VRegister & vd,const VRegister & vn)2388 void Assembler::uaddlp(const VRegister& vd, const VRegister& vn) {
2389 NEONAddlp(vd, vn, NEON_UADDLP);
2390 }
2391
sadalp(const VRegister & vd,const VRegister & vn)2392 void Assembler::sadalp(const VRegister& vd, const VRegister& vn) {
2393 NEONAddlp(vd, vn, NEON_SADALP);
2394 }
2395
uadalp(const VRegister & vd,const VRegister & vn)2396 void Assembler::uadalp(const VRegister& vd, const VRegister& vn) {
2397 NEONAddlp(vd, vn, NEON_UADALP);
2398 }
2399
NEONAcrossLanesL(const VRegister & vd,const VRegister & vn,NEONAcrossLanesOp op)2400 void Assembler::NEONAcrossLanesL(const VRegister& vd, const VRegister& vn,
2401 NEONAcrossLanesOp op) {
2402 DCHECK((vn.Is8B() && vd.Is1H()) || (vn.Is16B() && vd.Is1H()) ||
2403 (vn.Is4H() && vd.Is1S()) || (vn.Is8H() && vd.Is1S()) ||
2404 (vn.Is4S() && vd.Is1D()));
2405 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
2406 }
2407
saddlv(const VRegister & vd,const VRegister & vn)2408 void Assembler::saddlv(const VRegister& vd, const VRegister& vn) {
2409 NEONAcrossLanesL(vd, vn, NEON_SADDLV);
2410 }
2411
uaddlv(const VRegister & vd,const VRegister & vn)2412 void Assembler::uaddlv(const VRegister& vd, const VRegister& vn) {
2413 NEONAcrossLanesL(vd, vn, NEON_UADDLV);
2414 }
2415
NEONAcrossLanes(const VRegister & vd,const VRegister & vn,NEONAcrossLanesOp op)2416 void Assembler::NEONAcrossLanes(const VRegister& vd, const VRegister& vn,
2417 NEONAcrossLanesOp op) {
2418 DCHECK((vn.Is8B() && vd.Is1B()) || (vn.Is16B() && vd.Is1B()) ||
2419 (vn.Is4H() && vd.Is1H()) || (vn.Is8H() && vd.Is1H()) ||
2420 (vn.Is4S() && vd.Is1S()));
2421 if ((op & NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
2422 Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));
2423 } else {
2424 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));
2425 }
2426 }
2427
2428 #define NEON_ACROSSLANES_LIST(V) \
2429 V(fmaxv, NEON_FMAXV, vd.Is1S()) \
2430 V(fminv, NEON_FMINV, vd.Is1S()) \
2431 V(fmaxnmv, NEON_FMAXNMV, vd.Is1S()) \
2432 V(fminnmv, NEON_FMINNMV, vd.Is1S()) \
2433 V(addv, NEON_ADDV, true) \
2434 V(smaxv, NEON_SMAXV, true) \
2435 V(sminv, NEON_SMINV, true) \
2436 V(umaxv, NEON_UMAXV, true) \
2437 V(uminv, NEON_UMINV, true)
2438
2439 #define DEFINE_ASM_FUNC(FN, OP, AS) \
2440 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
2441 DCHECK(AS); \
2442 NEONAcrossLanes(vd, vn, OP); \
2443 }
NEON_ACROSSLANES_LIST(DEFINE_ASM_FUNC)2444 NEON_ACROSSLANES_LIST(DEFINE_ASM_FUNC)
2445 #undef DEFINE_ASM_FUNC
2446
2447 void Assembler::mov(const VRegister& vd, int vd_index, const Register& rn) {
2448 ins(vd, vd_index, rn);
2449 }
2450
umov(const Register & rd,const VRegister & vn,int vn_index)2451 void Assembler::umov(const Register& rd, const VRegister& vn, int vn_index) {
2452 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
2453 // number of lanes, and T is b, h, s or d.
2454 int lane_size = vn.LaneSizeInBytes();
2455 NEONFormatField format;
2456 Instr q = 0;
2457 switch (lane_size) {
2458 case 1:
2459 format = NEON_16B;
2460 DCHECK(rd.IsW());
2461 break;
2462 case 2:
2463 format = NEON_8H;
2464 DCHECK(rd.IsW());
2465 break;
2466 case 4:
2467 format = NEON_4S;
2468 DCHECK(rd.IsW());
2469 break;
2470 default:
2471 DCHECK_EQ(lane_size, 8);
2472 DCHECK(rd.IsX());
2473 format = NEON_2D;
2474 q = NEON_Q;
2475 break;
2476 }
2477
2478 DCHECK((0 <= vn_index) &&
2479 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
2480 Emit(q | NEON_UMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));
2481 }
2482
mov(const VRegister & vd,const VRegister & vn,int vn_index)2483 void Assembler::mov(const VRegister& vd, const VRegister& vn, int vn_index) {
2484 DCHECK(vd.IsScalar());
2485 dup(vd, vn, vn_index);
2486 }
2487
dup(const VRegister & vd,const Register & rn)2488 void Assembler::dup(const VRegister& vd, const Register& rn) {
2489 DCHECK(!vd.Is1D());
2490 DCHECK_EQ(vd.Is2D(), rn.IsX());
2491 Instr q = vd.IsD() ? 0 : NEON_Q;
2492 Emit(q | NEON_DUP_GENERAL | ImmNEON5(VFormat(vd), 0) | Rn(rn) | Rd(vd));
2493 }
2494
ins(const VRegister & vd,int vd_index,const VRegister & vn,int vn_index)2495 void Assembler::ins(const VRegister& vd, int vd_index, const VRegister& vn,
2496 int vn_index) {
2497 DCHECK(AreSameFormat(vd, vn));
2498 // We support vd arguments of the form vd.VxT() or vd.T(), where x is the
2499 // number of lanes, and T is b, h, s or d.
2500 int lane_size = vd.LaneSizeInBytes();
2501 NEONFormatField format;
2502 switch (lane_size) {
2503 case 1:
2504 format = NEON_16B;
2505 break;
2506 case 2:
2507 format = NEON_8H;
2508 break;
2509 case 4:
2510 format = NEON_4S;
2511 break;
2512 default:
2513 DCHECK_EQ(lane_size, 8);
2514 format = NEON_2D;
2515 break;
2516 }
2517
2518 DCHECK((0 <= vd_index) &&
2519 (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
2520 DCHECK((0 <= vn_index) &&
2521 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));
2522 Emit(NEON_INS_ELEMENT | ImmNEON5(format, vd_index) |
2523 ImmNEON4(format, vn_index) | Rn(vn) | Rd(vd));
2524 }
2525
NEONTable(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEONTableOp op)2526 void Assembler::NEONTable(const VRegister& vd, const VRegister& vn,
2527 const VRegister& vm, NEONTableOp op) {
2528 DCHECK(vd.Is16B() || vd.Is8B());
2529 DCHECK(vn.Is16B());
2530 DCHECK(AreSameFormat(vd, vm));
2531 Emit(op | (vd.IsQ() ? NEON_Q : 0) | Rm(vm) | Rn(vn) | Rd(vd));
2532 }
2533
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vm)2534 void Assembler::tbl(const VRegister& vd, const VRegister& vn,
2535 const VRegister& vm) {
2536 NEONTable(vd, vn, vm, NEON_TBL_1v);
2537 }
2538
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vm)2539 void Assembler::tbl(const VRegister& vd, const VRegister& vn,
2540 const VRegister& vn2, const VRegister& vm) {
2541 USE(vn2);
2542 DCHECK(AreSameFormat(vn, vn2));
2543 DCHECK(AreConsecutive(vn, vn2));
2544 NEONTable(vd, vn, vm, NEON_TBL_2v);
2545 }
2546
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vm)2547 void Assembler::tbl(const VRegister& vd, const VRegister& vn,
2548 const VRegister& vn2, const VRegister& vn3,
2549 const VRegister& vm) {
2550 USE(vn2);
2551 USE(vn3);
2552 DCHECK(AreSameFormat(vn, vn2, vn3));
2553 DCHECK(AreConsecutive(vn, vn2, vn3));
2554 NEONTable(vd, vn, vm, NEON_TBL_3v);
2555 }
2556
tbl(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vn4,const VRegister & vm)2557 void Assembler::tbl(const VRegister& vd, const VRegister& vn,
2558 const VRegister& vn2, const VRegister& vn3,
2559 const VRegister& vn4, const VRegister& vm) {
2560 USE(vn2);
2561 USE(vn3);
2562 USE(vn4);
2563 DCHECK(AreSameFormat(vn, vn2, vn3, vn4));
2564 DCHECK(AreConsecutive(vn, vn2, vn3, vn4));
2565 NEONTable(vd, vn, vm, NEON_TBL_4v);
2566 }
2567
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vm)2568 void Assembler::tbx(const VRegister& vd, const VRegister& vn,
2569 const VRegister& vm) {
2570 NEONTable(vd, vn, vm, NEON_TBX_1v);
2571 }
2572
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vm)2573 void Assembler::tbx(const VRegister& vd, const VRegister& vn,
2574 const VRegister& vn2, const VRegister& vm) {
2575 USE(vn2);
2576 DCHECK(AreSameFormat(vn, vn2));
2577 DCHECK(AreConsecutive(vn, vn2));
2578 NEONTable(vd, vn, vm, NEON_TBX_2v);
2579 }
2580
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vm)2581 void Assembler::tbx(const VRegister& vd, const VRegister& vn,
2582 const VRegister& vn2, const VRegister& vn3,
2583 const VRegister& vm) {
2584 USE(vn2);
2585 USE(vn3);
2586 DCHECK(AreSameFormat(vn, vn2, vn3));
2587 DCHECK(AreConsecutive(vn, vn2, vn3));
2588 NEONTable(vd, vn, vm, NEON_TBX_3v);
2589 }
2590
tbx(const VRegister & vd,const VRegister & vn,const VRegister & vn2,const VRegister & vn3,const VRegister & vn4,const VRegister & vm)2591 void Assembler::tbx(const VRegister& vd, const VRegister& vn,
2592 const VRegister& vn2, const VRegister& vn3,
2593 const VRegister& vn4, const VRegister& vm) {
2594 USE(vn2);
2595 USE(vn3);
2596 USE(vn4);
2597 DCHECK(AreSameFormat(vn, vn2, vn3, vn4));
2598 DCHECK(AreConsecutive(vn, vn2, vn3, vn4));
2599 NEONTable(vd, vn, vm, NEON_TBX_4v);
2600 }
2601
mov(const VRegister & vd,int vd_index,const VRegister & vn,int vn_index)2602 void Assembler::mov(const VRegister& vd, int vd_index, const VRegister& vn,
2603 int vn_index) {
2604 ins(vd, vd_index, vn, vn_index);
2605 }
2606
mvn(const Register & rd,const Operand & operand)2607 void Assembler::mvn(const Register& rd, const Operand& operand) {
2608 orn(rd, AppropriateZeroRegFor(rd), operand);
2609 }
2610
mrs(const Register & rt,SystemRegister sysreg)2611 void Assembler::mrs(const Register& rt, SystemRegister sysreg) {
2612 DCHECK(rt.Is64Bits());
2613 Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt));
2614 }
2615
msr(SystemRegister sysreg,const Register & rt)2616 void Assembler::msr(SystemRegister sysreg, const Register& rt) {
2617 DCHECK(rt.Is64Bits());
2618 Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg));
2619 }
2620
hint(SystemHint code)2621 void Assembler::hint(SystemHint code) { Emit(HINT | ImmHint(code) | Rt(xzr)); }
2622
2623 // NEON structure loads and stores.
LoadStoreStructAddrModeField(const MemOperand & addr)2624 Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) {
2625 Instr addr_field = RnSP(addr.base());
2626
2627 if (addr.IsPostIndex()) {
2628 static_assert(NEONLoadStoreMultiStructPostIndex ==
2629 static_cast<NEONLoadStoreMultiStructPostIndexOp>(
2630 NEONLoadStoreSingleStructPostIndex),
2631 "Opcodes must match for NEON post index memop.");
2632
2633 addr_field |= NEONLoadStoreMultiStructPostIndex;
2634 if (addr.offset() == 0) {
2635 addr_field |= RmNot31(addr.regoffset());
2636 } else {
2637 // The immediate post index addressing mode is indicated by rm = 31.
2638 // The immediate is implied by the number of vector registers used.
2639 addr_field |= (0x1F << Rm_offset);
2640 }
2641 } else {
2642 DCHECK(addr.IsImmediateOffset() && (addr.offset() == 0));
2643 }
2644 return addr_field;
2645 }
2646
LoadStoreStructVerify(const VRegister & vt,const MemOperand & addr,Instr op)2647 void Assembler::LoadStoreStructVerify(const VRegister& vt,
2648 const MemOperand& addr, Instr op) {
2649 #ifdef DEBUG
2650 // Assert that addressing mode is either offset (with immediate 0), post
2651 // index by immediate of the size of the register list, or post index by a
2652 // value in a core register.
2653 if (addr.IsImmediateOffset()) {
2654 DCHECK_EQ(addr.offset(), 0);
2655 } else {
2656 int offset = vt.SizeInBytes();
2657 switch (op) {
2658 case NEON_LD1_1v:
2659 case NEON_ST1_1v:
2660 offset *= 1;
2661 break;
2662 case NEONLoadStoreSingleStructLoad1:
2663 case NEONLoadStoreSingleStructStore1:
2664 case NEON_LD1R:
2665 offset = (offset / vt.LaneCount()) * 1;
2666 break;
2667
2668 case NEON_LD1_2v:
2669 case NEON_ST1_2v:
2670 case NEON_LD2:
2671 case NEON_ST2:
2672 offset *= 2;
2673 break;
2674 case NEONLoadStoreSingleStructLoad2:
2675 case NEONLoadStoreSingleStructStore2:
2676 case NEON_LD2R:
2677 offset = (offset / vt.LaneCount()) * 2;
2678 break;
2679
2680 case NEON_LD1_3v:
2681 case NEON_ST1_3v:
2682 case NEON_LD3:
2683 case NEON_ST3:
2684 offset *= 3;
2685 break;
2686 case NEONLoadStoreSingleStructLoad3:
2687 case NEONLoadStoreSingleStructStore3:
2688 case NEON_LD3R:
2689 offset = (offset / vt.LaneCount()) * 3;
2690 break;
2691
2692 case NEON_LD1_4v:
2693 case NEON_ST1_4v:
2694 case NEON_LD4:
2695 case NEON_ST4:
2696 offset *= 4;
2697 break;
2698 case NEONLoadStoreSingleStructLoad4:
2699 case NEONLoadStoreSingleStructStore4:
2700 case NEON_LD4R:
2701 offset = (offset / vt.LaneCount()) * 4;
2702 break;
2703 default:
2704 UNREACHABLE();
2705 }
2706 DCHECK(!addr.regoffset().Is(NoReg) || addr.offset() == offset);
2707 }
2708 #else
2709 USE(vt);
2710 USE(addr);
2711 USE(op);
2712 #endif
2713 }
2714
LoadStoreStruct(const VRegister & vt,const MemOperand & addr,NEONLoadStoreMultiStructOp op)2715 void Assembler::LoadStoreStruct(const VRegister& vt, const MemOperand& addr,
2716 NEONLoadStoreMultiStructOp op) {
2717 LoadStoreStructVerify(vt, addr, op);
2718 DCHECK(vt.IsVector() || vt.Is1D());
2719 Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));
2720 }
2721
LoadStoreStructSingleAllLanes(const VRegister & vt,const MemOperand & addr,NEONLoadStoreSingleStructOp op)2722 void Assembler::LoadStoreStructSingleAllLanes(const VRegister& vt,
2723 const MemOperand& addr,
2724 NEONLoadStoreSingleStructOp op) {
2725 LoadStoreStructVerify(vt, addr, op);
2726 Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));
2727 }
2728
ld1(const VRegister & vt,const MemOperand & src)2729 void Assembler::ld1(const VRegister& vt, const MemOperand& src) {
2730 LoadStoreStruct(vt, src, NEON_LD1_1v);
2731 }
2732
ld1(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2733 void Assembler::ld1(const VRegister& vt, const VRegister& vt2,
2734 const MemOperand& src) {
2735 USE(vt2);
2736 DCHECK(AreSameFormat(vt, vt2));
2737 DCHECK(AreConsecutive(vt, vt2));
2738 LoadStoreStruct(vt, src, NEON_LD1_2v);
2739 }
2740
ld1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2741 void Assembler::ld1(const VRegister& vt, const VRegister& vt2,
2742 const VRegister& vt3, const MemOperand& src) {
2743 USE(vt2);
2744 USE(vt3);
2745 DCHECK(AreSameFormat(vt, vt2, vt3));
2746 DCHECK(AreConsecutive(vt, vt2, vt3));
2747 LoadStoreStruct(vt, src, NEON_LD1_3v);
2748 }
2749
ld1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2750 void Assembler::ld1(const VRegister& vt, const VRegister& vt2,
2751 const VRegister& vt3, const VRegister& vt4,
2752 const MemOperand& src) {
2753 USE(vt2);
2754 USE(vt3);
2755 USE(vt4);
2756 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2757 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2758 LoadStoreStruct(vt, src, NEON_LD1_4v);
2759 }
2760
ld2(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2761 void Assembler::ld2(const VRegister& vt, const VRegister& vt2,
2762 const MemOperand& src) {
2763 USE(vt2);
2764 DCHECK(AreSameFormat(vt, vt2));
2765 DCHECK(AreConsecutive(vt, vt2));
2766 LoadStoreStruct(vt, src, NEON_LD2);
2767 }
2768
ld2(const VRegister & vt,const VRegister & vt2,int lane,const MemOperand & src)2769 void Assembler::ld2(const VRegister& vt, const VRegister& vt2, int lane,
2770 const MemOperand& src) {
2771 USE(vt2);
2772 DCHECK(AreSameFormat(vt, vt2));
2773 DCHECK(AreConsecutive(vt, vt2));
2774 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad2);
2775 }
2776
ld2r(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2777 void Assembler::ld2r(const VRegister& vt, const VRegister& vt2,
2778 const MemOperand& src) {
2779 USE(vt2);
2780 DCHECK(AreSameFormat(vt, vt2));
2781 DCHECK(AreConsecutive(vt, vt2));
2782 LoadStoreStructSingleAllLanes(vt, src, NEON_LD2R);
2783 }
2784
ld3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2785 void Assembler::ld3(const VRegister& vt, const VRegister& vt2,
2786 const VRegister& vt3, const MemOperand& src) {
2787 USE(vt2);
2788 USE(vt3);
2789 DCHECK(AreSameFormat(vt, vt2, vt3));
2790 DCHECK(AreConsecutive(vt, vt2, vt3));
2791 LoadStoreStruct(vt, src, NEON_LD3);
2792 }
2793
ld3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,int lane,const MemOperand & src)2794 void Assembler::ld3(const VRegister& vt, const VRegister& vt2,
2795 const VRegister& vt3, int lane, const MemOperand& src) {
2796 USE(vt2);
2797 USE(vt3);
2798 DCHECK(AreSameFormat(vt, vt2, vt3));
2799 DCHECK(AreConsecutive(vt, vt2, vt3));
2800 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad3);
2801 }
2802
ld3r(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2803 void Assembler::ld3r(const VRegister& vt, const VRegister& vt2,
2804 const VRegister& vt3, const MemOperand& src) {
2805 USE(vt2);
2806 USE(vt3);
2807 DCHECK(AreSameFormat(vt, vt2, vt3));
2808 DCHECK(AreConsecutive(vt, vt2, vt3));
2809 LoadStoreStructSingleAllLanes(vt, src, NEON_LD3R);
2810 }
2811
ld4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2812 void Assembler::ld4(const VRegister& vt, const VRegister& vt2,
2813 const VRegister& vt3, const VRegister& vt4,
2814 const MemOperand& src) {
2815 USE(vt2);
2816 USE(vt3);
2817 USE(vt4);
2818 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2819 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2820 LoadStoreStruct(vt, src, NEON_LD4);
2821 }
2822
ld4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,int lane,const MemOperand & src)2823 void Assembler::ld4(const VRegister& vt, const VRegister& vt2,
2824 const VRegister& vt3, const VRegister& vt4, int lane,
2825 const MemOperand& src) {
2826 USE(vt2);
2827 USE(vt3);
2828 USE(vt4);
2829 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2830 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2831 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad4);
2832 }
2833
ld4r(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2834 void Assembler::ld4r(const VRegister& vt, const VRegister& vt2,
2835 const VRegister& vt3, const VRegister& vt4,
2836 const MemOperand& src) {
2837 USE(vt2);
2838 USE(vt3);
2839 USE(vt4);
2840 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2841 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2842 LoadStoreStructSingleAllLanes(vt, src, NEON_LD4R);
2843 }
2844
st1(const VRegister & vt,const MemOperand & src)2845 void Assembler::st1(const VRegister& vt, const MemOperand& src) {
2846 LoadStoreStruct(vt, src, NEON_ST1_1v);
2847 }
2848
st1(const VRegister & vt,const VRegister & vt2,const MemOperand & src)2849 void Assembler::st1(const VRegister& vt, const VRegister& vt2,
2850 const MemOperand& src) {
2851 USE(vt2);
2852 DCHECK(AreSameFormat(vt, vt2));
2853 DCHECK(AreConsecutive(vt, vt2));
2854 LoadStoreStruct(vt, src, NEON_ST1_2v);
2855 }
2856
st1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & src)2857 void Assembler::st1(const VRegister& vt, const VRegister& vt2,
2858 const VRegister& vt3, const MemOperand& src) {
2859 USE(vt2);
2860 USE(vt3);
2861 DCHECK(AreSameFormat(vt, vt2, vt3));
2862 DCHECK(AreConsecutive(vt, vt2, vt3));
2863 LoadStoreStruct(vt, src, NEON_ST1_3v);
2864 }
2865
st1(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & src)2866 void Assembler::st1(const VRegister& vt, const VRegister& vt2,
2867 const VRegister& vt3, const VRegister& vt4,
2868 const MemOperand& src) {
2869 USE(vt2);
2870 USE(vt3);
2871 USE(vt4);
2872 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2873 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2874 LoadStoreStruct(vt, src, NEON_ST1_4v);
2875 }
2876
st2(const VRegister & vt,const VRegister & vt2,const MemOperand & dst)2877 void Assembler::st2(const VRegister& vt, const VRegister& vt2,
2878 const MemOperand& dst) {
2879 USE(vt2);
2880 DCHECK(AreSameFormat(vt, vt2));
2881 DCHECK(AreConsecutive(vt, vt2));
2882 LoadStoreStruct(vt, dst, NEON_ST2);
2883 }
2884
st2(const VRegister & vt,const VRegister & vt2,int lane,const MemOperand & dst)2885 void Assembler::st2(const VRegister& vt, const VRegister& vt2, int lane,
2886 const MemOperand& dst) {
2887 USE(vt2);
2888 DCHECK(AreSameFormat(vt, vt2));
2889 DCHECK(AreConsecutive(vt, vt2));
2890 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore2);
2891 }
2892
st3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const MemOperand & dst)2893 void Assembler::st3(const VRegister& vt, const VRegister& vt2,
2894 const VRegister& vt3, const MemOperand& dst) {
2895 USE(vt2);
2896 USE(vt3);
2897 DCHECK(AreSameFormat(vt, vt2, vt3));
2898 DCHECK(AreConsecutive(vt, vt2, vt3));
2899 LoadStoreStruct(vt, dst, NEON_ST3);
2900 }
2901
st3(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,int lane,const MemOperand & dst)2902 void Assembler::st3(const VRegister& vt, const VRegister& vt2,
2903 const VRegister& vt3, int lane, const MemOperand& dst) {
2904 USE(vt2);
2905 USE(vt3);
2906 DCHECK(AreSameFormat(vt, vt2, vt3));
2907 DCHECK(AreConsecutive(vt, vt2, vt3));
2908 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore3);
2909 }
2910
st4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,const MemOperand & dst)2911 void Assembler::st4(const VRegister& vt, const VRegister& vt2,
2912 const VRegister& vt3, const VRegister& vt4,
2913 const MemOperand& dst) {
2914 USE(vt2);
2915 USE(vt3);
2916 USE(vt4);
2917 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2918 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2919 LoadStoreStruct(vt, dst, NEON_ST4);
2920 }
2921
st4(const VRegister & vt,const VRegister & vt2,const VRegister & vt3,const VRegister & vt4,int lane,const MemOperand & dst)2922 void Assembler::st4(const VRegister& vt, const VRegister& vt2,
2923 const VRegister& vt3, const VRegister& vt4, int lane,
2924 const MemOperand& dst) {
2925 USE(vt2);
2926 USE(vt3);
2927 USE(vt4);
2928 DCHECK(AreSameFormat(vt, vt2, vt3, vt4));
2929 DCHECK(AreConsecutive(vt, vt2, vt3, vt4));
2930 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore4);
2931 }
2932
LoadStoreStructSingle(const VRegister & vt,uint32_t lane,const MemOperand & addr,NEONLoadStoreSingleStructOp op)2933 void Assembler::LoadStoreStructSingle(const VRegister& vt, uint32_t lane,
2934 const MemOperand& addr,
2935 NEONLoadStoreSingleStructOp op) {
2936 LoadStoreStructVerify(vt, addr, op);
2937
2938 // We support vt arguments of the form vt.VxT() or vt.T(), where x is the
2939 // number of lanes, and T is b, h, s or d.
2940 unsigned lane_size = vt.LaneSizeInBytes();
2941 DCHECK_LT(lane, kQRegSize / lane_size);
2942
2943 // Lane size is encoded in the opcode field. Lane index is encoded in the Q,
2944 // S and size fields.
2945 lane *= lane_size;
2946
2947 // Encodings for S[0]/D[0] and S[2]/D[1] are distinguished using the least-
2948 // significant bit of the size field, so we increment lane here to account for
2949 // that.
2950 if (lane_size == 8) lane++;
2951
2952 Instr size = (lane << NEONLSSize_offset) & NEONLSSize_mask;
2953 Instr s = (lane << (NEONS_offset - 2)) & NEONS_mask;
2954 Instr q = (lane << (NEONQ_offset - 3)) & NEONQ_mask;
2955
2956 Instr instr = op;
2957 switch (lane_size) {
2958 case 1:
2959 instr |= NEONLoadStoreSingle_b;
2960 break;
2961 case 2:
2962 instr |= NEONLoadStoreSingle_h;
2963 break;
2964 case 4:
2965 instr |= NEONLoadStoreSingle_s;
2966 break;
2967 default:
2968 DCHECK_EQ(lane_size, 8U);
2969 instr |= NEONLoadStoreSingle_d;
2970 }
2971
2972 Emit(instr | LoadStoreStructAddrModeField(addr) | q | size | s | Rt(vt));
2973 }
2974
ld1(const VRegister & vt,int lane,const MemOperand & src)2975 void Assembler::ld1(const VRegister& vt, int lane, const MemOperand& src) {
2976 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad1);
2977 }
2978
ld1r(const VRegister & vt,const MemOperand & src)2979 void Assembler::ld1r(const VRegister& vt, const MemOperand& src) {
2980 LoadStoreStructSingleAllLanes(vt, src, NEON_LD1R);
2981 }
2982
st1(const VRegister & vt,int lane,const MemOperand & dst)2983 void Assembler::st1(const VRegister& vt, int lane, const MemOperand& dst) {
2984 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore1);
2985 }
2986
dmb(BarrierDomain domain,BarrierType type)2987 void Assembler::dmb(BarrierDomain domain, BarrierType type) {
2988 Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));
2989 }
2990
dsb(BarrierDomain domain,BarrierType type)2991 void Assembler::dsb(BarrierDomain domain, BarrierType type) {
2992 Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));
2993 }
2994
isb()2995 void Assembler::isb() {
2996 Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));
2997 }
2998
csdb()2999 void Assembler::csdb() { hint(CSDB); }
3000
fmov(const VRegister & vd,double imm)3001 void Assembler::fmov(const VRegister& vd, double imm) {
3002 if (vd.IsScalar()) {
3003 DCHECK(vd.Is1D());
3004 Emit(FMOV_d_imm | Rd(vd) | ImmFP(imm));
3005 } else {
3006 DCHECK(vd.Is2D());
3007 Instr op = NEONModifiedImmediate_MOVI | NEONModifiedImmediateOpBit;
3008 Emit(NEON_Q | op | ImmNEONFP(imm) | NEONCmode(0xF) | Rd(vd));
3009 }
3010 }
3011
fmov(const VRegister & vd,float imm)3012 void Assembler::fmov(const VRegister& vd, float imm) {
3013 if (vd.IsScalar()) {
3014 DCHECK(vd.Is1S());
3015 Emit(FMOV_s_imm | Rd(vd) | ImmFP(imm));
3016 } else {
3017 DCHECK(vd.Is2S() | vd.Is4S());
3018 Instr op = NEONModifiedImmediate_MOVI;
3019 Instr q = vd.Is4S() ? NEON_Q : 0;
3020 Emit(q | op | ImmNEONFP(imm) | NEONCmode(0xF) | Rd(vd));
3021 }
3022 }
3023
fmov(const Register & rd,const VRegister & fn)3024 void Assembler::fmov(const Register& rd, const VRegister& fn) {
3025 DCHECK_EQ(rd.SizeInBits(), fn.SizeInBits());
3026 FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd;
3027 Emit(op | Rd(rd) | Rn(fn));
3028 }
3029
fmov(const VRegister & vd,const Register & rn)3030 void Assembler::fmov(const VRegister& vd, const Register& rn) {
3031 DCHECK_EQ(vd.SizeInBits(), rn.SizeInBits());
3032 FPIntegerConvertOp op = vd.Is32Bits() ? FMOV_sw : FMOV_dx;
3033 Emit(op | Rd(vd) | Rn(rn));
3034 }
3035
fmov(const VRegister & vd,const VRegister & vn)3036 void Assembler::fmov(const VRegister& vd, const VRegister& vn) {
3037 DCHECK_EQ(vd.SizeInBits(), vn.SizeInBits());
3038 Emit(FPType(vd) | FMOV | Rd(vd) | Rn(vn));
3039 }
3040
fmov(const VRegister & vd,int index,const Register & rn)3041 void Assembler::fmov(const VRegister& vd, int index, const Register& rn) {
3042 DCHECK((index == 1) && vd.Is1D() && rn.IsX());
3043 USE(index);
3044 Emit(FMOV_d1_x | Rd(vd) | Rn(rn));
3045 }
3046
fmov(const Register & rd,const VRegister & vn,int index)3047 void Assembler::fmov(const Register& rd, const VRegister& vn, int index) {
3048 DCHECK((index == 1) && vn.Is1D() && rd.IsX());
3049 USE(index);
3050 Emit(FMOV_x_d1 | Rd(rd) | Rn(vn));
3051 }
3052
fmadd(const VRegister & fd,const VRegister & fn,const VRegister & fm,const VRegister & fa)3053 void Assembler::fmadd(const VRegister& fd, const VRegister& fn,
3054 const VRegister& fm, const VRegister& fa) {
3055 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d);
3056 }
3057
fmsub(const VRegister & fd,const VRegister & fn,const VRegister & fm,const VRegister & fa)3058 void Assembler::fmsub(const VRegister& fd, const VRegister& fn,
3059 const VRegister& fm, const VRegister& fa) {
3060 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d);
3061 }
3062
fnmadd(const VRegister & fd,const VRegister & fn,const VRegister & fm,const VRegister & fa)3063 void Assembler::fnmadd(const VRegister& fd, const VRegister& fn,
3064 const VRegister& fm, const VRegister& fa) {
3065 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d);
3066 }
3067
fnmsub(const VRegister & fd,const VRegister & fn,const VRegister & fm,const VRegister & fa)3068 void Assembler::fnmsub(const VRegister& fd, const VRegister& fn,
3069 const VRegister& fm, const VRegister& fa) {
3070 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d);
3071 }
3072
fnmul(const VRegister & vd,const VRegister & vn,const VRegister & vm)3073 void Assembler::fnmul(const VRegister& vd, const VRegister& vn,
3074 const VRegister& vm) {
3075 DCHECK(AreSameSizeAndType(vd, vn, vm));
3076 Instr op = vd.Is1S() ? FNMUL_s : FNMUL_d;
3077 Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
3078 }
3079
fcmp(const VRegister & fn,const VRegister & fm)3080 void Assembler::fcmp(const VRegister& fn, const VRegister& fm) {
3081 DCHECK_EQ(fn.SizeInBits(), fm.SizeInBits());
3082 Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn));
3083 }
3084
fcmp(const VRegister & fn,double value)3085 void Assembler::fcmp(const VRegister& fn, double value) {
3086 USE(value);
3087 // Although the fcmp instruction can strictly only take an immediate value of
3088 // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't
3089 // affect the result of the comparison.
3090 DCHECK_EQ(value, 0.0);
3091 Emit(FPType(fn) | FCMP_zero | Rn(fn));
3092 }
3093
fccmp(const VRegister & fn,const VRegister & fm,StatusFlags nzcv,Condition cond)3094 void Assembler::fccmp(const VRegister& fn, const VRegister& fm,
3095 StatusFlags nzcv, Condition cond) {
3096 DCHECK_EQ(fn.SizeInBits(), fm.SizeInBits());
3097 Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv));
3098 }
3099
fcsel(const VRegister & fd,const VRegister & fn,const VRegister & fm,Condition cond)3100 void Assembler::fcsel(const VRegister& fd, const VRegister& fn,
3101 const VRegister& fm, Condition cond) {
3102 DCHECK_EQ(fd.SizeInBits(), fn.SizeInBits());
3103 DCHECK_EQ(fd.SizeInBits(), fm.SizeInBits());
3104 Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd));
3105 }
3106
NEONFPConvertToInt(const Register & rd,const VRegister & vn,Instr op)3107 void Assembler::NEONFPConvertToInt(const Register& rd, const VRegister& vn,
3108 Instr op) {
3109 Emit(SF(rd) | FPType(vn) | op | Rn(vn) | Rd(rd));
3110 }
3111
NEONFPConvertToInt(const VRegister & vd,const VRegister & vn,Instr op)3112 void Assembler::NEONFPConvertToInt(const VRegister& vd, const VRegister& vn,
3113 Instr op) {
3114 if (vn.IsScalar()) {
3115 DCHECK((vd.Is1S() && vn.Is1S()) || (vd.Is1D() && vn.Is1D()));
3116 op |= NEON_Q | NEONScalar;
3117 }
3118 Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));
3119 }
3120
fcvt(const VRegister & vd,const VRegister & vn)3121 void Assembler::fcvt(const VRegister& vd, const VRegister& vn) {
3122 FPDataProcessing1SourceOp op;
3123 if (vd.Is1D()) {
3124 DCHECK(vn.Is1S() || vn.Is1H());
3125 op = vn.Is1S() ? FCVT_ds : FCVT_dh;
3126 } else if (vd.Is1S()) {
3127 DCHECK(vn.Is1D() || vn.Is1H());
3128 op = vn.Is1D() ? FCVT_sd : FCVT_sh;
3129 } else {
3130 DCHECK(vd.Is1H());
3131 DCHECK(vn.Is1D() || vn.Is1S());
3132 op = vn.Is1D() ? FCVT_hd : FCVT_hs;
3133 }
3134 FPDataProcessing1Source(vd, vn, op);
3135 }
3136
fcvtl(const VRegister & vd,const VRegister & vn)3137 void Assembler::fcvtl(const VRegister& vd, const VRegister& vn) {
3138 DCHECK((vd.Is4S() && vn.Is4H()) || (vd.Is2D() && vn.Is2S()));
3139 Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;
3140 Emit(format | NEON_FCVTL | Rn(vn) | Rd(vd));
3141 }
3142
fcvtl2(const VRegister & vd,const VRegister & vn)3143 void Assembler::fcvtl2(const VRegister& vd, const VRegister& vn) {
3144 DCHECK((vd.Is4S() && vn.Is8H()) || (vd.Is2D() && vn.Is4S()));
3145 Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;
3146 Emit(NEON_Q | format | NEON_FCVTL | Rn(vn) | Rd(vd));
3147 }
3148
fcvtn(const VRegister & vd,const VRegister & vn)3149 void Assembler::fcvtn(const VRegister& vd, const VRegister& vn) {
3150 DCHECK((vn.Is4S() && vd.Is4H()) || (vn.Is2D() && vd.Is2S()));
3151 Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;
3152 Emit(format | NEON_FCVTN | Rn(vn) | Rd(vd));
3153 }
3154
fcvtn2(const VRegister & vd,const VRegister & vn)3155 void Assembler::fcvtn2(const VRegister& vd, const VRegister& vn) {
3156 DCHECK((vn.Is4S() && vd.Is8H()) || (vn.Is2D() && vd.Is4S()));
3157 Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;
3158 Emit(NEON_Q | format | NEON_FCVTN | Rn(vn) | Rd(vd));
3159 }
3160
fcvtxn(const VRegister & vd,const VRegister & vn)3161 void Assembler::fcvtxn(const VRegister& vd, const VRegister& vn) {
3162 Instr format = 1 << NEONSize_offset;
3163 if (vd.IsScalar()) {
3164 DCHECK(vd.Is1S() && vn.Is1D());
3165 Emit(format | NEON_FCVTXN_scalar | Rn(vn) | Rd(vd));
3166 } else {
3167 DCHECK(vd.Is2S() && vn.Is2D());
3168 Emit(format | NEON_FCVTXN | Rn(vn) | Rd(vd));
3169 }
3170 }
3171
fcvtxn2(const VRegister & vd,const VRegister & vn)3172 void Assembler::fcvtxn2(const VRegister& vd, const VRegister& vn) {
3173 DCHECK(vd.Is4S() && vn.Is2D());
3174 Instr format = 1 << NEONSize_offset;
3175 Emit(NEON_Q | format | NEON_FCVTXN | Rn(vn) | Rd(vd));
3176 }
3177
3178 #define NEON_FP2REGMISC_FCVT_LIST(V) \
3179 V(fcvtnu, NEON_FCVTNU, FCVTNU) \
3180 V(fcvtns, NEON_FCVTNS, FCVTNS) \
3181 V(fcvtpu, NEON_FCVTPU, FCVTPU) \
3182 V(fcvtps, NEON_FCVTPS, FCVTPS) \
3183 V(fcvtmu, NEON_FCVTMU, FCVTMU) \
3184 V(fcvtms, NEON_FCVTMS, FCVTMS) \
3185 V(fcvtau, NEON_FCVTAU, FCVTAU) \
3186 V(fcvtas, NEON_FCVTAS, FCVTAS)
3187
3188 #define DEFINE_ASM_FUNCS(FN, VEC_OP, SCA_OP) \
3189 void Assembler::FN(const Register& rd, const VRegister& vn) { \
3190 NEONFPConvertToInt(rd, vn, SCA_OP); \
3191 } \
3192 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
3193 NEONFPConvertToInt(vd, vn, VEC_OP); \
3194 }
NEON_FP2REGMISC_FCVT_LIST(DEFINE_ASM_FUNCS)3195 NEON_FP2REGMISC_FCVT_LIST(DEFINE_ASM_FUNCS)
3196 #undef DEFINE_ASM_FUNCS
3197
3198 void Assembler::scvtf(const VRegister& vd, const VRegister& vn, int fbits) {
3199 DCHECK_GE(fbits, 0);
3200 if (fbits == 0) {
3201 NEONFP2RegMisc(vd, vn, NEON_SCVTF);
3202 } else {
3203 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S());
3204 NEONShiftRightImmediate(vd, vn, fbits, NEON_SCVTF_imm);
3205 }
3206 }
3207
ucvtf(const VRegister & vd,const VRegister & vn,int fbits)3208 void Assembler::ucvtf(const VRegister& vd, const VRegister& vn, int fbits) {
3209 DCHECK_GE(fbits, 0);
3210 if (fbits == 0) {
3211 NEONFP2RegMisc(vd, vn, NEON_UCVTF);
3212 } else {
3213 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S());
3214 NEONShiftRightImmediate(vd, vn, fbits, NEON_UCVTF_imm);
3215 }
3216 }
3217
scvtf(const VRegister & vd,const Register & rn,int fbits)3218 void Assembler::scvtf(const VRegister& vd, const Register& rn, int fbits) {
3219 DCHECK_GE(fbits, 0);
3220 if (fbits == 0) {
3221 Emit(SF(rn) | FPType(vd) | SCVTF | Rn(rn) | Rd(vd));
3222 } else {
3223 Emit(SF(rn) | FPType(vd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
3224 Rd(vd));
3225 }
3226 }
3227
ucvtf(const VRegister & fd,const Register & rn,int fbits)3228 void Assembler::ucvtf(const VRegister& fd, const Register& rn, int fbits) {
3229 DCHECK_GE(fbits, 0);
3230 if (fbits == 0) {
3231 Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd));
3232 } else {
3233 Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
3234 Rd(fd));
3235 }
3236 }
3237
NEON3Same(const VRegister & vd,const VRegister & vn,const VRegister & vm,NEON3SameOp vop)3238 void Assembler::NEON3Same(const VRegister& vd, const VRegister& vn,
3239 const VRegister& vm, NEON3SameOp vop) {
3240 DCHECK(AreSameFormat(vd, vn, vm));
3241 DCHECK(vd.IsVector() || !vd.IsQ());
3242
3243 Instr format, op = vop;
3244 if (vd.IsScalar()) {
3245 op |= NEON_Q | NEONScalar;
3246 format = SFormat(vd);
3247 } else {
3248 format = VFormat(vd);
3249 }
3250
3251 Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));
3252 }
3253
NEONFP3Same(const VRegister & vd,const VRegister & vn,const VRegister & vm,Instr op)3254 void Assembler::NEONFP3Same(const VRegister& vd, const VRegister& vn,
3255 const VRegister& vm, Instr op) {
3256 DCHECK(AreSameFormat(vd, vn, vm));
3257 Emit(FPFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));
3258 }
3259
3260 #define NEON_FP2REGMISC_LIST(V) \
3261 V(fabs, NEON_FABS, FABS) \
3262 V(fneg, NEON_FNEG, FNEG) \
3263 V(fsqrt, NEON_FSQRT, FSQRT) \
3264 V(frintn, NEON_FRINTN, FRINTN) \
3265 V(frinta, NEON_FRINTA, FRINTA) \
3266 V(frintp, NEON_FRINTP, FRINTP) \
3267 V(frintm, NEON_FRINTM, FRINTM) \
3268 V(frintx, NEON_FRINTX, FRINTX) \
3269 V(frintz, NEON_FRINTZ, FRINTZ) \
3270 V(frinti, NEON_FRINTI, FRINTI) \
3271 V(frsqrte, NEON_FRSQRTE, NEON_FRSQRTE_scalar) \
3272 V(frecpe, NEON_FRECPE, NEON_FRECPE_scalar)
3273
3274 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \
3275 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \
3276 Instr op; \
3277 if (vd.IsScalar()) { \
3278 DCHECK(vd.Is1S() || vd.Is1D()); \
3279 op = SCA_OP; \
3280 } else { \
3281 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S()); \
3282 op = VEC_OP; \
3283 } \
3284 NEONFP2RegMisc(vd, vn, op); \
3285 }
NEON_FP2REGMISC_LIST(DEFINE_ASM_FUNC)3286 NEON_FP2REGMISC_LIST(DEFINE_ASM_FUNC)
3287 #undef DEFINE_ASM_FUNC
3288
3289 void Assembler::shll(const VRegister& vd, const VRegister& vn, int shift) {
3290 DCHECK((vd.Is8H() && vn.Is8B() && shift == 8) ||
3291 (vd.Is4S() && vn.Is4H() && shift == 16) ||
3292 (vd.Is2D() && vn.Is2S() && shift == 32));
3293 USE(shift);
3294 Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));
3295 }
3296
shll2(const VRegister & vd,const VRegister & vn,int shift)3297 void Assembler::shll2(const VRegister& vd, const VRegister& vn, int shift) {
3298 USE(shift);
3299 DCHECK((vd.Is8H() && vn.Is16B() && shift == 8) ||
3300 (vd.Is4S() && vn.Is8H() && shift == 16) ||
3301 (vd.Is2D() && vn.Is4S() && shift == 32));
3302 Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));
3303 }
3304
NEONFP2RegMisc(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop,double value)3305 void Assembler::NEONFP2RegMisc(const VRegister& vd, const VRegister& vn,
3306 NEON2RegMiscOp vop, double value) {
3307 DCHECK(AreSameFormat(vd, vn));
3308 DCHECK_EQ(value, 0.0);
3309 USE(value);
3310
3311 Instr op = vop;
3312 if (vd.IsScalar()) {
3313 DCHECK(vd.Is1S() || vd.Is1D());
3314 op |= NEON_Q | NEONScalar;
3315 } else {
3316 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S());
3317 }
3318
3319 Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));
3320 }
3321
fcmeq(const VRegister & vd,const VRegister & vn,double value)3322 void Assembler::fcmeq(const VRegister& vd, const VRegister& vn, double value) {
3323 NEONFP2RegMisc(vd, vn, NEON_FCMEQ_zero, value);
3324 }
3325
fcmge(const VRegister & vd,const VRegister & vn,double value)3326 void Assembler::fcmge(const VRegister& vd, const VRegister& vn, double value) {
3327 NEONFP2RegMisc(vd, vn, NEON_FCMGE_zero, value);
3328 }
3329
fcmgt(const VRegister & vd,const VRegister & vn,double value)3330 void Assembler::fcmgt(const VRegister& vd, const VRegister& vn, double value) {
3331 NEONFP2RegMisc(vd, vn, NEON_FCMGT_zero, value);
3332 }
3333
fcmle(const VRegister & vd,const VRegister & vn,double value)3334 void Assembler::fcmle(const VRegister& vd, const VRegister& vn, double value) {
3335 NEONFP2RegMisc(vd, vn, NEON_FCMLE_zero, value);
3336 }
3337
fcmlt(const VRegister & vd,const VRegister & vn,double value)3338 void Assembler::fcmlt(const VRegister& vd, const VRegister& vn, double value) {
3339 NEONFP2RegMisc(vd, vn, NEON_FCMLT_zero, value);
3340 }
3341
frecpx(const VRegister & vd,const VRegister & vn)3342 void Assembler::frecpx(const VRegister& vd, const VRegister& vn) {
3343 DCHECK(vd.IsScalar());
3344 DCHECK(AreSameFormat(vd, vn));
3345 DCHECK(vd.Is1S() || vd.Is1D());
3346 Emit(FPFormat(vd) | NEON_FRECPX_scalar | Rn(vn) | Rd(vd));
3347 }
3348
fcvtzs(const Register & rd,const VRegister & vn,int fbits)3349 void Assembler::fcvtzs(const Register& rd, const VRegister& vn, int fbits) {
3350 DCHECK(vn.Is1S() || vn.Is1D());
3351 DCHECK((fbits >= 0) && (fbits <= rd.SizeInBits()));
3352 if (fbits == 0) {
3353 Emit(SF(rd) | FPType(vn) | FCVTZS | Rn(vn) | Rd(rd));
3354 } else {
3355 Emit(SF(rd) | FPType(vn) | FCVTZS_fixed | FPScale(64 - fbits) | Rn(vn) |
3356 Rd(rd));
3357 }
3358 }
3359
fcvtzs(const VRegister & vd,const VRegister & vn,int fbits)3360 void Assembler::fcvtzs(const VRegister& vd, const VRegister& vn, int fbits) {
3361 DCHECK_GE(fbits, 0);
3362 if (fbits == 0) {
3363 NEONFP2RegMisc(vd, vn, NEON_FCVTZS);
3364 } else {
3365 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S());
3366 NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZS_imm);
3367 }
3368 }
3369
fcvtzu(const Register & rd,const VRegister & vn,int fbits)3370 void Assembler::fcvtzu(const Register& rd, const VRegister& vn, int fbits) {
3371 DCHECK(vn.Is1S() || vn.Is1D());
3372 DCHECK((fbits >= 0) && (fbits <= rd.SizeInBits()));
3373 if (fbits == 0) {
3374 Emit(SF(rd) | FPType(vn) | FCVTZU | Rn(vn) | Rd(rd));
3375 } else {
3376 Emit(SF(rd) | FPType(vn) | FCVTZU_fixed | FPScale(64 - fbits) | Rn(vn) |
3377 Rd(rd));
3378 }
3379 }
3380
fcvtzu(const VRegister & vd,const VRegister & vn,int fbits)3381 void Assembler::fcvtzu(const VRegister& vd, const VRegister& vn, int fbits) {
3382 DCHECK_GE(fbits, 0);
3383 if (fbits == 0) {
3384 NEONFP2RegMisc(vd, vn, NEON_FCVTZU);
3385 } else {
3386 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S());
3387 NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZU_imm);
3388 }
3389 }
3390
NEONFP2RegMisc(const VRegister & vd,const VRegister & vn,Instr op)3391 void Assembler::NEONFP2RegMisc(const VRegister& vd, const VRegister& vn,
3392 Instr op) {
3393 DCHECK(AreSameFormat(vd, vn));
3394 Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));
3395 }
3396
NEON2RegMisc(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop,int value)3397 void Assembler::NEON2RegMisc(const VRegister& vd, const VRegister& vn,
3398 NEON2RegMiscOp vop, int value) {
3399 DCHECK(AreSameFormat(vd, vn));
3400 DCHECK_EQ(value, 0);
3401 USE(value);
3402
3403 Instr format, op = vop;
3404 if (vd.IsScalar()) {
3405 op |= NEON_Q | NEONScalar;
3406 format = SFormat(vd);
3407 } else {
3408 format = VFormat(vd);
3409 }
3410
3411 Emit(format | op | Rn(vn) | Rd(vd));
3412 }
3413
cmeq(const VRegister & vd,const VRegister & vn,int value)3414 void Assembler::cmeq(const VRegister& vd, const VRegister& vn, int value) {
3415 DCHECK(vd.IsVector() || vd.Is1D());
3416 NEON2RegMisc(vd, vn, NEON_CMEQ_zero, value);
3417 }
3418
cmge(const VRegister & vd,const VRegister & vn,int value)3419 void Assembler::cmge(const VRegister& vd, const VRegister& vn, int value) {
3420 DCHECK(vd.IsVector() || vd.Is1D());
3421 NEON2RegMisc(vd, vn, NEON_CMGE_zero, value);
3422 }
3423
cmgt(const VRegister & vd,const VRegister & vn,int value)3424 void Assembler::cmgt(const VRegister& vd, const VRegister& vn, int value) {
3425 DCHECK(vd.IsVector() || vd.Is1D());
3426 NEON2RegMisc(vd, vn, NEON_CMGT_zero, value);
3427 }
3428
cmle(const VRegister & vd,const VRegister & vn,int value)3429 void Assembler::cmle(const VRegister& vd, const VRegister& vn, int value) {
3430 DCHECK(vd.IsVector() || vd.Is1D());
3431 NEON2RegMisc(vd, vn, NEON_CMLE_zero, value);
3432 }
3433
cmlt(const VRegister & vd,const VRegister & vn,int value)3434 void Assembler::cmlt(const VRegister& vd, const VRegister& vn, int value) {
3435 DCHECK(vd.IsVector() || vd.Is1D());
3436 NEON2RegMisc(vd, vn, NEON_CMLT_zero, value);
3437 }
3438
3439 #define NEON_3SAME_LIST(V) \
3440 V(add, NEON_ADD, vd.IsVector() || vd.Is1D()) \
3441 V(addp, NEON_ADDP, vd.IsVector() || vd.Is1D()) \
3442 V(sub, NEON_SUB, vd.IsVector() || vd.Is1D()) \
3443 V(cmeq, NEON_CMEQ, vd.IsVector() || vd.Is1D()) \
3444 V(cmge, NEON_CMGE, vd.IsVector() || vd.Is1D()) \
3445 V(cmgt, NEON_CMGT, vd.IsVector() || vd.Is1D()) \
3446 V(cmhi, NEON_CMHI, vd.IsVector() || vd.Is1D()) \
3447 V(cmhs, NEON_CMHS, vd.IsVector() || vd.Is1D()) \
3448 V(cmtst, NEON_CMTST, vd.IsVector() || vd.Is1D()) \
3449 V(sshl, NEON_SSHL, vd.IsVector() || vd.Is1D()) \
3450 V(ushl, NEON_USHL, vd.IsVector() || vd.Is1D()) \
3451 V(srshl, NEON_SRSHL, vd.IsVector() || vd.Is1D()) \
3452 V(urshl, NEON_URSHL, vd.IsVector() || vd.Is1D()) \
3453 V(sqdmulh, NEON_SQDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \
3454 V(sqrdmulh, NEON_SQRDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \
3455 V(shadd, NEON_SHADD, vd.IsVector() && !vd.IsLaneSizeD()) \
3456 V(uhadd, NEON_UHADD, vd.IsVector() && !vd.IsLaneSizeD()) \
3457 V(srhadd, NEON_SRHADD, vd.IsVector() && !vd.IsLaneSizeD()) \
3458 V(urhadd, NEON_URHADD, vd.IsVector() && !vd.IsLaneSizeD()) \
3459 V(shsub, NEON_SHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \
3460 V(uhsub, NEON_UHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \
3461 V(smax, NEON_SMAX, vd.IsVector() && !vd.IsLaneSizeD()) \
3462 V(smaxp, NEON_SMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \
3463 V(smin, NEON_SMIN, vd.IsVector() && !vd.IsLaneSizeD()) \
3464 V(sminp, NEON_SMINP, vd.IsVector() && !vd.IsLaneSizeD()) \
3465 V(umax, NEON_UMAX, vd.IsVector() && !vd.IsLaneSizeD()) \
3466 V(umaxp, NEON_UMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \
3467 V(umin, NEON_UMIN, vd.IsVector() && !vd.IsLaneSizeD()) \
3468 V(uminp, NEON_UMINP, vd.IsVector() && !vd.IsLaneSizeD()) \
3469 V(saba, NEON_SABA, vd.IsVector() && !vd.IsLaneSizeD()) \
3470 V(sabd, NEON_SABD, vd.IsVector() && !vd.IsLaneSizeD()) \
3471 V(uaba, NEON_UABA, vd.IsVector() && !vd.IsLaneSizeD()) \
3472 V(uabd, NEON_UABD, vd.IsVector() && !vd.IsLaneSizeD()) \
3473 V(mla, NEON_MLA, vd.IsVector() && !vd.IsLaneSizeD()) \
3474 V(mls, NEON_MLS, vd.IsVector() && !vd.IsLaneSizeD()) \
3475 V(mul, NEON_MUL, vd.IsVector() && !vd.IsLaneSizeD()) \
3476 V(and_, NEON_AND, vd.Is8B() || vd.Is16B()) \
3477 V(orr, NEON_ORR, vd.Is8B() || vd.Is16B()) \
3478 V(orn, NEON_ORN, vd.Is8B() || vd.Is16B()) \
3479 V(eor, NEON_EOR, vd.Is8B() || vd.Is16B()) \
3480 V(bic, NEON_BIC, vd.Is8B() || vd.Is16B()) \
3481 V(bit, NEON_BIT, vd.Is8B() || vd.Is16B()) \
3482 V(bif, NEON_BIF, vd.Is8B() || vd.Is16B()) \
3483 V(bsl, NEON_BSL, vd.Is8B() || vd.Is16B()) \
3484 V(pmul, NEON_PMUL, vd.Is8B() || vd.Is16B()) \
3485 V(uqadd, NEON_UQADD, true) \
3486 V(sqadd, NEON_SQADD, true) \
3487 V(uqsub, NEON_UQSUB, true) \
3488 V(sqsub, NEON_SQSUB, true) \
3489 V(sqshl, NEON_SQSHL, true) \
3490 V(uqshl, NEON_UQSHL, true) \
3491 V(sqrshl, NEON_SQRSHL, true) \
3492 V(uqrshl, NEON_UQRSHL, true)
3493
3494 #define DEFINE_ASM_FUNC(FN, OP, AS) \
3495 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
3496 const VRegister& vm) { \
3497 DCHECK(AS); \
3498 NEON3Same(vd, vn, vm, OP); \
3499 }
3500 NEON_3SAME_LIST(DEFINE_ASM_FUNC)
3501 #undef DEFINE_ASM_FUNC
3502
3503 #define NEON_FP3SAME_LIST_V2(V) \
3504 V(fadd, NEON_FADD, FADD) \
3505 V(fsub, NEON_FSUB, FSUB) \
3506 V(fmul, NEON_FMUL, FMUL) \
3507 V(fdiv, NEON_FDIV, FDIV) \
3508 V(fmax, NEON_FMAX, FMAX) \
3509 V(fmaxnm, NEON_FMAXNM, FMAXNM) \
3510 V(fmin, NEON_FMIN, FMIN) \
3511 V(fminnm, NEON_FMINNM, FMINNM) \
3512 V(fmulx, NEON_FMULX, NEON_FMULX_scalar) \
3513 V(frecps, NEON_FRECPS, NEON_FRECPS_scalar) \
3514 V(frsqrts, NEON_FRSQRTS, NEON_FRSQRTS_scalar) \
3515 V(fabd, NEON_FABD, NEON_FABD_scalar) \
3516 V(fmla, NEON_FMLA, 0) \
3517 V(fmls, NEON_FMLS, 0) \
3518 V(facge, NEON_FACGE, NEON_FACGE_scalar) \
3519 V(facgt, NEON_FACGT, NEON_FACGT_scalar) \
3520 V(fcmeq, NEON_FCMEQ, NEON_FCMEQ_scalar) \
3521 V(fcmge, NEON_FCMGE, NEON_FCMGE_scalar) \
3522 V(fcmgt, NEON_FCMGT, NEON_FCMGT_scalar) \
3523 V(faddp, NEON_FADDP, 0) \
3524 V(fmaxp, NEON_FMAXP, 0) \
3525 V(fminp, NEON_FMINP, 0) \
3526 V(fmaxnmp, NEON_FMAXNMP, 0) \
3527 V(fminnmp, NEON_FMINNMP, 0)
3528
3529 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \
3530 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
3531 const VRegister& vm) { \
3532 Instr op; \
3533 if ((SCA_OP != 0) && vd.IsScalar()) { \
3534 DCHECK(vd.Is1S() || vd.Is1D()); \
3535 op = SCA_OP; \
3536 } else { \
3537 DCHECK(vd.IsVector()); \
3538 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S()); \
3539 op = VEC_OP; \
3540 } \
3541 NEONFP3Same(vd, vn, vm, op); \
3542 }
NEON_FP3SAME_LIST_V2(DEFINE_ASM_FUNC)3543 NEON_FP3SAME_LIST_V2(DEFINE_ASM_FUNC)
3544 #undef DEFINE_ASM_FUNC
3545
3546 void Assembler::addp(const VRegister& vd, const VRegister& vn) {
3547 DCHECK((vd.Is1D() && vn.Is2D()));
3548 Emit(SFormat(vd) | NEON_ADDP_scalar | Rn(vn) | Rd(vd));
3549 }
3550
faddp(const VRegister & vd,const VRegister & vn)3551 void Assembler::faddp(const VRegister& vd, const VRegister& vn) {
3552 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()));
3553 Emit(FPFormat(vd) | NEON_FADDP_scalar | Rn(vn) | Rd(vd));
3554 }
3555
fmaxp(const VRegister & vd,const VRegister & vn)3556 void Assembler::fmaxp(const VRegister& vd, const VRegister& vn) {
3557 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()));
3558 Emit(FPFormat(vd) | NEON_FMAXP_scalar | Rn(vn) | Rd(vd));
3559 }
3560
fminp(const VRegister & vd,const VRegister & vn)3561 void Assembler::fminp(const VRegister& vd, const VRegister& vn) {
3562 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()));
3563 Emit(FPFormat(vd) | NEON_FMINP_scalar | Rn(vn) | Rd(vd));
3564 }
3565
fmaxnmp(const VRegister & vd,const VRegister & vn)3566 void Assembler::fmaxnmp(const VRegister& vd, const VRegister& vn) {
3567 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()));
3568 Emit(FPFormat(vd) | NEON_FMAXNMP_scalar | Rn(vn) | Rd(vd));
3569 }
3570
fminnmp(const VRegister & vd,const VRegister & vn)3571 void Assembler::fminnmp(const VRegister& vd, const VRegister& vn) {
3572 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()));
3573 Emit(FPFormat(vd) | NEON_FMINNMP_scalar | Rn(vn) | Rd(vd));
3574 }
3575
orr(const VRegister & vd,const int imm8,const int left_shift)3576 void Assembler::orr(const VRegister& vd, const int imm8, const int left_shift) {
3577 NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_ORR);
3578 }
3579
mov(const VRegister & vd,const VRegister & vn)3580 void Assembler::mov(const VRegister& vd, const VRegister& vn) {
3581 DCHECK(AreSameFormat(vd, vn));
3582 if (vd.IsD()) {
3583 orr(vd.V8B(), vn.V8B(), vn.V8B());
3584 } else {
3585 DCHECK(vd.IsQ());
3586 orr(vd.V16B(), vn.V16B(), vn.V16B());
3587 }
3588 }
3589
bic(const VRegister & vd,const int imm8,const int left_shift)3590 void Assembler::bic(const VRegister& vd, const int imm8, const int left_shift) {
3591 NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_BIC);
3592 }
3593
movi(const VRegister & vd,const uint64_t imm,Shift shift,const int shift_amount)3594 void Assembler::movi(const VRegister& vd, const uint64_t imm, Shift shift,
3595 const int shift_amount) {
3596 DCHECK((shift == LSL) || (shift == MSL));
3597 if (vd.Is2D() || vd.Is1D()) {
3598 DCHECK_EQ(shift_amount, 0);
3599 int imm8 = 0;
3600 for (int i = 0; i < 8; ++i) {
3601 int byte = (imm >> (i * 8)) & 0xFF;
3602 DCHECK((byte == 0) || (byte == 0xFF));
3603 if (byte == 0xFF) {
3604 imm8 |= (1 << i);
3605 }
3606 }
3607 Instr q = vd.Is2D() ? NEON_Q : 0;
3608 Emit(q | NEONModImmOp(1) | NEONModifiedImmediate_MOVI |
3609 ImmNEONabcdefgh(imm8) | NEONCmode(0xE) | Rd(vd));
3610 } else if (shift == LSL) {
3611 NEONModifiedImmShiftLsl(vd, static_cast<int>(imm), shift_amount,
3612 NEONModifiedImmediate_MOVI);
3613 } else {
3614 NEONModifiedImmShiftMsl(vd, static_cast<int>(imm), shift_amount,
3615 NEONModifiedImmediate_MOVI);
3616 }
3617 }
3618
mvn(const VRegister & vd,const VRegister & vn)3619 void Assembler::mvn(const VRegister& vd, const VRegister& vn) {
3620 DCHECK(AreSameFormat(vd, vn));
3621 if (vd.IsD()) {
3622 not_(vd.V8B(), vn.V8B());
3623 } else {
3624 DCHECK(vd.IsQ());
3625 not_(vd.V16B(), vn.V16B());
3626 }
3627 }
3628
mvni(const VRegister & vd,const int imm8,Shift shift,const int shift_amount)3629 void Assembler::mvni(const VRegister& vd, const int imm8, Shift shift,
3630 const int shift_amount) {
3631 DCHECK((shift == LSL) || (shift == MSL));
3632 if (shift == LSL) {
3633 NEONModifiedImmShiftLsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);
3634 } else {
3635 NEONModifiedImmShiftMsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);
3636 }
3637 }
3638
NEONFPByElement(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop)3639 void Assembler::NEONFPByElement(const VRegister& vd, const VRegister& vn,
3640 const VRegister& vm, int vm_index,
3641 NEONByIndexedElementOp vop) {
3642 DCHECK(AreSameFormat(vd, vn));
3643 DCHECK((vd.Is2S() && vm.Is1S()) || (vd.Is4S() && vm.Is1S()) ||
3644 (vd.Is1S() && vm.Is1S()) || (vd.Is2D() && vm.Is1D()) ||
3645 (vd.Is1D() && vm.Is1D()));
3646 DCHECK((vm.Is1S() && (vm_index < 4)) || (vm.Is1D() && (vm_index < 2)));
3647
3648 Instr op = vop;
3649 int index_num_bits = vm.Is1S() ? 2 : 1;
3650 if (vd.IsScalar()) {
3651 op |= NEON_Q | NEONScalar;
3652 }
3653
3654 Emit(FPFormat(vd) | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) |
3655 Rn(vn) | Rd(vd));
3656 }
3657
NEONByElement(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop)3658 void Assembler::NEONByElement(const VRegister& vd, const VRegister& vn,
3659 const VRegister& vm, int vm_index,
3660 NEONByIndexedElementOp vop) {
3661 DCHECK(AreSameFormat(vd, vn));
3662 DCHECK((vd.Is4H() && vm.Is1H()) || (vd.Is8H() && vm.Is1H()) ||
3663 (vd.Is1H() && vm.Is1H()) || (vd.Is2S() && vm.Is1S()) ||
3664 (vd.Is4S() && vm.Is1S()) || (vd.Is1S() && vm.Is1S()));
3665 DCHECK((vm.Is1H() && (vm.code() < 16) && (vm_index < 8)) ||
3666 (vm.Is1S() && (vm_index < 4)));
3667
3668 Instr format, op = vop;
3669 int index_num_bits = vm.Is1H() ? 3 : 2;
3670 if (vd.IsScalar()) {
3671 op |= NEONScalar | NEON_Q;
3672 format = SFormat(vn);
3673 } else {
3674 format = VFormat(vn);
3675 }
3676 Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |
3677 Rd(vd));
3678 }
3679
NEONByElementL(const VRegister & vd,const VRegister & vn,const VRegister & vm,int vm_index,NEONByIndexedElementOp vop)3680 void Assembler::NEONByElementL(const VRegister& vd, const VRegister& vn,
3681 const VRegister& vm, int vm_index,
3682 NEONByIndexedElementOp vop) {
3683 DCHECK((vd.Is4S() && vn.Is4H() && vm.Is1H()) ||
3684 (vd.Is4S() && vn.Is8H() && vm.Is1H()) ||
3685 (vd.Is1S() && vn.Is1H() && vm.Is1H()) ||
3686 (vd.Is2D() && vn.Is2S() && vm.Is1S()) ||
3687 (vd.Is2D() && vn.Is4S() && vm.Is1S()) ||
3688 (vd.Is1D() && vn.Is1S() && vm.Is1S()));
3689
3690 DCHECK((vm.Is1H() && (vm.code() < 16) && (vm_index < 8)) ||
3691 (vm.Is1S() && (vm_index < 4)));
3692
3693 Instr format, op = vop;
3694 int index_num_bits = vm.Is1H() ? 3 : 2;
3695 if (vd.IsScalar()) {
3696 op |= NEONScalar | NEON_Q;
3697 format = SFormat(vn);
3698 } else {
3699 format = VFormat(vn);
3700 }
3701 Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |
3702 Rd(vd));
3703 }
3704
3705 #define NEON_BYELEMENT_LIST(V) \
3706 V(mul, NEON_MUL_byelement, vn.IsVector()) \
3707 V(mla, NEON_MLA_byelement, vn.IsVector()) \
3708 V(mls, NEON_MLS_byelement, vn.IsVector()) \
3709 V(sqdmulh, NEON_SQDMULH_byelement, true) \
3710 V(sqrdmulh, NEON_SQRDMULH_byelement, true)
3711
3712 #define DEFINE_ASM_FUNC(FN, OP, AS) \
3713 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
3714 const VRegister& vm, int vm_index) { \
3715 DCHECK(AS); \
3716 NEONByElement(vd, vn, vm, vm_index, OP); \
3717 }
3718 NEON_BYELEMENT_LIST(DEFINE_ASM_FUNC)
3719 #undef DEFINE_ASM_FUNC
3720
3721 #define NEON_FPBYELEMENT_LIST(V) \
3722 V(fmul, NEON_FMUL_byelement) \
3723 V(fmla, NEON_FMLA_byelement) \
3724 V(fmls, NEON_FMLS_byelement) \
3725 V(fmulx, NEON_FMULX_byelement)
3726
3727 #define DEFINE_ASM_FUNC(FN, OP) \
3728 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
3729 const VRegister& vm, int vm_index) { \
3730 NEONFPByElement(vd, vn, vm, vm_index, OP); \
3731 }
NEON_FPBYELEMENT_LIST(DEFINE_ASM_FUNC)3732 NEON_FPBYELEMENT_LIST(DEFINE_ASM_FUNC)
3733 #undef DEFINE_ASM_FUNC
3734
3735 #define NEON_BYELEMENT_LONG_LIST(V) \
3736 V(sqdmull, NEON_SQDMULL_byelement, vn.IsScalar() || vn.IsD()) \
3737 V(sqdmull2, NEON_SQDMULL_byelement, vn.IsVector() && vn.IsQ()) \
3738 V(sqdmlal, NEON_SQDMLAL_byelement, vn.IsScalar() || vn.IsD()) \
3739 V(sqdmlal2, NEON_SQDMLAL_byelement, vn.IsVector() && vn.IsQ()) \
3740 V(sqdmlsl, NEON_SQDMLSL_byelement, vn.IsScalar() || vn.IsD()) \
3741 V(sqdmlsl2, NEON_SQDMLSL_byelement, vn.IsVector() && vn.IsQ()) \
3742 V(smull, NEON_SMULL_byelement, vn.IsVector() && vn.IsD()) \
3743 V(smull2, NEON_SMULL_byelement, vn.IsVector() && vn.IsQ()) \
3744 V(umull, NEON_UMULL_byelement, vn.IsVector() && vn.IsD()) \
3745 V(umull2, NEON_UMULL_byelement, vn.IsVector() && vn.IsQ()) \
3746 V(smlal, NEON_SMLAL_byelement, vn.IsVector() && vn.IsD()) \
3747 V(smlal2, NEON_SMLAL_byelement, vn.IsVector() && vn.IsQ()) \
3748 V(umlal, NEON_UMLAL_byelement, vn.IsVector() && vn.IsD()) \
3749 V(umlal2, NEON_UMLAL_byelement, vn.IsVector() && vn.IsQ()) \
3750 V(smlsl, NEON_SMLSL_byelement, vn.IsVector() && vn.IsD()) \
3751 V(smlsl2, NEON_SMLSL_byelement, vn.IsVector() && vn.IsQ()) \
3752 V(umlsl, NEON_UMLSL_byelement, vn.IsVector() && vn.IsD()) \
3753 V(umlsl2, NEON_UMLSL_byelement, vn.IsVector() && vn.IsQ())
3754
3755 #define DEFINE_ASM_FUNC(FN, OP, AS) \
3756 void Assembler::FN(const VRegister& vd, const VRegister& vn, \
3757 const VRegister& vm, int vm_index) { \
3758 DCHECK(AS); \
3759 NEONByElementL(vd, vn, vm, vm_index, OP); \
3760 }
3761 NEON_BYELEMENT_LONG_LIST(DEFINE_ASM_FUNC)
3762 #undef DEFINE_ASM_FUNC
3763
3764 void Assembler::suqadd(const VRegister& vd, const VRegister& vn) {
3765 NEON2RegMisc(vd, vn, NEON_SUQADD);
3766 }
3767
usqadd(const VRegister & vd,const VRegister & vn)3768 void Assembler::usqadd(const VRegister& vd, const VRegister& vn) {
3769 NEON2RegMisc(vd, vn, NEON_USQADD);
3770 }
3771
abs(const VRegister & vd,const VRegister & vn)3772 void Assembler::abs(const VRegister& vd, const VRegister& vn) {
3773 DCHECK(vd.IsVector() || vd.Is1D());
3774 NEON2RegMisc(vd, vn, NEON_ABS);
3775 }
3776
sqabs(const VRegister & vd,const VRegister & vn)3777 void Assembler::sqabs(const VRegister& vd, const VRegister& vn) {
3778 NEON2RegMisc(vd, vn, NEON_SQABS);
3779 }
3780
neg(const VRegister & vd,const VRegister & vn)3781 void Assembler::neg(const VRegister& vd, const VRegister& vn) {
3782 DCHECK(vd.IsVector() || vd.Is1D());
3783 NEON2RegMisc(vd, vn, NEON_NEG);
3784 }
3785
sqneg(const VRegister & vd,const VRegister & vn)3786 void Assembler::sqneg(const VRegister& vd, const VRegister& vn) {
3787 NEON2RegMisc(vd, vn, NEON_SQNEG);
3788 }
3789
NEONXtn(const VRegister & vd,const VRegister & vn,NEON2RegMiscOp vop)3790 void Assembler::NEONXtn(const VRegister& vd, const VRegister& vn,
3791 NEON2RegMiscOp vop) {
3792 Instr format, op = vop;
3793 if (vd.IsScalar()) {
3794 DCHECK((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||
3795 (vd.Is1S() && vn.Is1D()));
3796 op |= NEON_Q | NEONScalar;
3797 format = SFormat(vd);
3798 } else {
3799 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||
3800 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||
3801 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));
3802 format = VFormat(vd);
3803 }
3804 Emit(format | op | Rn(vn) | Rd(vd));
3805 }
3806
xtn(const VRegister & vd,const VRegister & vn)3807 void Assembler::xtn(const VRegister& vd, const VRegister& vn) {
3808 DCHECK(vd.IsVector() && vd.IsD());
3809 NEONXtn(vd, vn, NEON_XTN);
3810 }
3811
xtn2(const VRegister & vd,const VRegister & vn)3812 void Assembler::xtn2(const VRegister& vd, const VRegister& vn) {
3813 DCHECK(vd.IsVector() && vd.IsQ());
3814 NEONXtn(vd, vn, NEON_XTN);
3815 }
3816
sqxtn(const VRegister & vd,const VRegister & vn)3817 void Assembler::sqxtn(const VRegister& vd, const VRegister& vn) {
3818 DCHECK(vd.IsScalar() || vd.IsD());
3819 NEONXtn(vd, vn, NEON_SQXTN);
3820 }
3821
sqxtn2(const VRegister & vd,const VRegister & vn)3822 void Assembler::sqxtn2(const VRegister& vd, const VRegister& vn) {
3823 DCHECK(vd.IsVector() && vd.IsQ());
3824 NEONXtn(vd, vn, NEON_SQXTN);
3825 }
3826
sqxtun(const VRegister & vd,const VRegister & vn)3827 void Assembler::sqxtun(const VRegister& vd, const VRegister& vn) {
3828 DCHECK(vd.IsScalar() || vd.IsD());
3829 NEONXtn(vd, vn, NEON_SQXTUN);
3830 }
3831
sqxtun2(const VRegister & vd,const VRegister & vn)3832 void Assembler::sqxtun2(const VRegister& vd, const VRegister& vn) {
3833 DCHECK(vd.IsVector() && vd.IsQ());
3834 NEONXtn(vd, vn, NEON_SQXTUN);
3835 }
3836
uqxtn(const VRegister & vd,const VRegister & vn)3837 void Assembler::uqxtn(const VRegister& vd, const VRegister& vn) {
3838 DCHECK(vd.IsScalar() || vd.IsD());
3839 NEONXtn(vd, vn, NEON_UQXTN);
3840 }
3841
uqxtn2(const VRegister & vd,const VRegister & vn)3842 void Assembler::uqxtn2(const VRegister& vd, const VRegister& vn) {
3843 DCHECK(vd.IsVector() && vd.IsQ());
3844 NEONXtn(vd, vn, NEON_UQXTN);
3845 }
3846
3847 // NEON NOT and RBIT are distinguised by bit 22, the bottom bit of "size".
not_(const VRegister & vd,const VRegister & vn)3848 void Assembler::not_(const VRegister& vd, const VRegister& vn) {
3849 DCHECK(AreSameFormat(vd, vn));
3850 DCHECK(vd.Is8B() || vd.Is16B());
3851 Emit(VFormat(vd) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));
3852 }
3853
rbit(const VRegister & vd,const VRegister & vn)3854 void Assembler::rbit(const VRegister& vd, const VRegister& vn) {
3855 DCHECK(AreSameFormat(vd, vn));
3856 DCHECK(vd.Is8B() || vd.Is16B());
3857 Emit(VFormat(vn) | (1 << NEONSize_offset) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));
3858 }
3859
ext(const VRegister & vd,const VRegister & vn,const VRegister & vm,int index)3860 void Assembler::ext(const VRegister& vd, const VRegister& vn,
3861 const VRegister& vm, int index) {
3862 DCHECK(AreSameFormat(vd, vn, vm));
3863 DCHECK(vd.Is8B() || vd.Is16B());
3864 DCHECK((0 <= index) && (index < vd.LaneCount()));
3865 Emit(VFormat(vd) | NEON_EXT | Rm(vm) | ImmNEONExt(index) | Rn(vn) | Rd(vd));
3866 }
3867
dup(const VRegister & vd,const VRegister & vn,int vn_index)3868 void Assembler::dup(const VRegister& vd, const VRegister& vn, int vn_index) {
3869 Instr q, scalar;
3870
3871 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the
3872 // number of lanes, and T is b, h, s or d.
3873 int lane_size = vn.LaneSizeInBytes();
3874 NEONFormatField format;
3875 switch (lane_size) {
3876 case 1:
3877 format = NEON_16B;
3878 break;
3879 case 2:
3880 format = NEON_8H;
3881 break;
3882 case 4:
3883 format = NEON_4S;
3884 break;
3885 default:
3886 DCHECK_EQ(lane_size, 8);
3887 format = NEON_2D;
3888 break;
3889 }
3890
3891 if (vd.IsScalar()) {
3892 q = NEON_Q;
3893 scalar = NEONScalar;
3894 } else {
3895 DCHECK(!vd.Is1D());
3896 q = vd.IsD() ? 0 : NEON_Q;
3897 scalar = 0;
3898 }
3899 Emit(q | scalar | NEON_DUP_ELEMENT | ImmNEON5(format, vn_index) | Rn(vn) |
3900 Rd(vd));
3901 }
3902
dcptr(Label * label)3903 void Assembler::dcptr(Label* label) {
3904 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3905 if (label->is_bound()) {
3906 // The label is bound, so it does not need to be updated and the internal
3907 // reference should be emitted.
3908 //
3909 // In this case, label->pos() returns the offset of the label from the
3910 // start of the buffer.
3911 internal_reference_positions_.push_back(pc_offset());
3912 dc64(reinterpret_cast<uintptr_t>(buffer_ + label->pos()));
3913 } else {
3914 int32_t offset;
3915 if (label->is_linked()) {
3916 // The label is linked, so the internal reference should be added
3917 // onto the end of the label's link chain.
3918 //
3919 // In this case, label->pos() returns the offset of the last linked
3920 // instruction from the start of the buffer.
3921 offset = label->pos() - pc_offset();
3922 DCHECK_NE(offset, kStartOfLabelLinkChain);
3923 } else {
3924 // The label is unused, so it now becomes linked and the internal
3925 // reference is at the start of the new link chain.
3926 offset = kStartOfLabelLinkChain;
3927 }
3928 // The instruction at pc is now the last link in the label's chain.
3929 label->link_to(pc_offset());
3930
3931 // Traditionally the offset to the previous instruction in the chain is
3932 // encoded in the instruction payload (e.g. branch range) but internal
3933 // references are not instructions so while unbound they are encoded as
3934 // two consecutive brk instructions. The two 16-bit immediates are used
3935 // to encode the offset.
3936 offset >>= kInstrSizeLog2;
3937 DCHECK(is_int32(offset));
3938 uint32_t high16 = unsigned_bitextract_32(31, 16, offset);
3939 uint32_t low16 = unsigned_bitextract_32(15, 0, offset);
3940
3941 brk(high16);
3942 brk(low16);
3943 }
3944 }
3945
3946 // Below, a difference in case for the same letter indicates a
3947 // negated bit. If b is 1, then B is 0.
FPToImm8(double imm)3948 uint32_t Assembler::FPToImm8(double imm) {
3949 DCHECK(IsImmFP64(imm));
3950 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
3951 // 0000.0000.0000.0000.0000.0000.0000.0000
3952 uint64_t bits = bit_cast<uint64_t>(imm);
3953 // bit7: a000.0000
3954 uint64_t bit7 = ((bits >> 63) & 0x1) << 7;
3955 // bit6: 0b00.0000
3956 uint64_t bit6 = ((bits >> 61) & 0x1) << 6;
3957 // bit5_to_0: 00cd.efgh
3958 uint64_t bit5_to_0 = (bits >> 48) & 0x3F;
3959
3960 return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);
3961 }
3962
ImmFP(double imm)3963 Instr Assembler::ImmFP(double imm) { return FPToImm8(imm) << ImmFP_offset; }
ImmNEONFP(double imm)3964 Instr Assembler::ImmNEONFP(double imm) {
3965 return ImmNEONabcdefgh(FPToImm8(imm));
3966 }
3967
3968 // Code generation helpers.
MoveWide(const Register & rd,uint64_t imm,int shift,MoveWideImmediateOp mov_op)3969 void Assembler::MoveWide(const Register& rd, uint64_t imm, int shift,
3970 MoveWideImmediateOp mov_op) {
3971 // Ignore the top 32 bits of an immediate if we're moving to a W register.
3972 if (rd.Is32Bits()) {
3973 // Check that the top 32 bits are zero (a positive 32-bit number) or top
3974 // 33 bits are one (a negative 32-bit number, sign extended to 64 bits).
3975 DCHECK(((imm >> kWRegSizeInBits) == 0) ||
3976 ((imm >> (kWRegSizeInBits - 1)) == 0x1FFFFFFFF));
3977 imm &= kWRegMask;
3978 }
3979
3980 if (shift >= 0) {
3981 // Explicit shift specified.
3982 DCHECK((shift == 0) || (shift == 16) || (shift == 32) || (shift == 48));
3983 DCHECK(rd.Is64Bits() || (shift == 0) || (shift == 16));
3984 shift /= 16;
3985 } else {
3986 // Calculate a new immediate and shift combination to encode the immediate
3987 // argument.
3988 shift = 0;
3989 if ((imm & ~0xFFFFUL) == 0) {
3990 // Nothing to do.
3991 } else if ((imm & ~(0xFFFFUL << 16)) == 0) {
3992 imm >>= 16;
3993 shift = 1;
3994 } else if ((imm & ~(0xFFFFUL << 32)) == 0) {
3995 DCHECK(rd.Is64Bits());
3996 imm >>= 32;
3997 shift = 2;
3998 } else if ((imm & ~(0xFFFFUL << 48)) == 0) {
3999 DCHECK(rd.Is64Bits());
4000 imm >>= 48;
4001 shift = 3;
4002 }
4003 }
4004
4005 DCHECK(is_uint16(imm));
4006
4007 Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) |
4008 ImmMoveWide(static_cast<int>(imm)) | ShiftMoveWide(shift));
4009 }
4010
AddSub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)4011 void Assembler::AddSub(const Register& rd, const Register& rn,
4012 const Operand& operand, FlagsUpdate S, AddSubOp op) {
4013 DCHECK_EQ(rd.SizeInBits(), rn.SizeInBits());
4014 DCHECK(!operand.NeedsRelocation(this));
4015 if (operand.IsImmediate()) {
4016 int64_t immediate = operand.ImmediateValue();
4017 DCHECK(IsImmAddSub(immediate));
4018 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
4019 Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |
4020 ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn));
4021 } else if (operand.IsShiftedRegister()) {
4022 DCHECK_EQ(operand.reg().SizeInBits(), rd.SizeInBits());
4023 DCHECK_NE(operand.shift(), ROR);
4024
4025 // For instructions of the form:
4026 // add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ]
4027 // add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ]
4028 // add/sub wsp, wsp, <Wm> [, LSL #0-3 ]
4029 // adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]
4030 // or their 64-bit register equivalents, convert the operand from shifted to
4031 // extended register mode, and emit an add/sub extended instruction.
4032 if (rn.IsSP() || rd.IsSP()) {
4033 DCHECK(!(rd.IsSP() && (S == SetFlags)));
4034 DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S,
4035 AddSubExtendedFixed | op);
4036 } else {
4037 DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op);
4038 }
4039 } else {
4040 DCHECK(operand.IsExtendedRegister());
4041 DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op);
4042 }
4043 }
4044
AddSubWithCarry(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)4045 void Assembler::AddSubWithCarry(const Register& rd, const Register& rn,
4046 const Operand& operand, FlagsUpdate S,
4047 AddSubWithCarryOp op) {
4048 DCHECK_EQ(rd.SizeInBits(), rn.SizeInBits());
4049 DCHECK_EQ(rd.SizeInBits(), operand.reg().SizeInBits());
4050 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
4051 DCHECK(!operand.NeedsRelocation(this));
4052 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd));
4053 }
4054
hlt(int code)4055 void Assembler::hlt(int code) {
4056 DCHECK(is_uint16(code));
4057 Emit(HLT | ImmException(code));
4058 }
4059
brk(int code)4060 void Assembler::brk(int code) {
4061 DCHECK(is_uint16(code));
4062 Emit(BRK | ImmException(code));
4063 }
4064
EmitStringData(const char * string)4065 void Assembler::EmitStringData(const char* string) {
4066 size_t len = strlen(string) + 1;
4067 DCHECK_LE(RoundUp(len, kInstrSize), static_cast<size_t>(kGap));
4068 EmitData(string, static_cast<int>(len));
4069 // Pad with nullptr characters until pc_ is aligned.
4070 const char pad[] = {'\0', '\0', '\0', '\0'};
4071 static_assert(sizeof(pad) == kInstrSize,
4072 "Size of padding must match instruction size.");
4073 EmitData(pad, RoundUp(pc_offset(), kInstrSize) - pc_offset());
4074 }
4075
4076
debug(const char * message,uint32_t code,Instr params)4077 void Assembler::debug(const char* message, uint32_t code, Instr params) {
4078 #ifdef USE_SIMULATOR
4079 if (options().enable_simulator_code) {
4080 // The arguments to the debug marker need to be contiguous in memory, so
4081 // make sure we don't try to emit pools.
4082 BlockPoolsScope scope(this);
4083
4084 Label start;
4085 bind(&start);
4086
4087 // Refer to instructions-arm64.h for a description of the marker and its
4088 // arguments.
4089 hlt(kImmExceptionIsDebug);
4090 DCHECK_EQ(SizeOfCodeGeneratedSince(&start), kDebugCodeOffset);
4091 dc32(code);
4092 DCHECK_EQ(SizeOfCodeGeneratedSince(&start), kDebugParamsOffset);
4093 dc32(params);
4094 DCHECK_EQ(SizeOfCodeGeneratedSince(&start), kDebugMessageOffset);
4095 EmitStringData(message);
4096 hlt(kImmExceptionIsUnreachable);
4097
4098 return;
4099 }
4100 // Fall through if Serializer is enabled.
4101 #else
4102 // Make sure we haven't dynamically enabled simulator code when there is no
4103 // simulator built in.
4104 DCHECK(!options().enable_simulator_code);
4105 #endif
4106
4107 if (params & BREAK) {
4108 brk(0);
4109 }
4110 }
4111
4112
Logical(const Register & rd,const Register & rn,const Operand & operand,LogicalOp op)4113 void Assembler::Logical(const Register& rd,
4114 const Register& rn,
4115 const Operand& operand,
4116 LogicalOp op) {
4117 DCHECK(rd.SizeInBits() == rn.SizeInBits());
4118 DCHECK(!operand.NeedsRelocation(this));
4119 if (operand.IsImmediate()) {
4120 int64_t immediate = operand.ImmediateValue();
4121 unsigned reg_size = rd.SizeInBits();
4122
4123 DCHECK_NE(immediate, 0);
4124 DCHECK_NE(immediate, -1);
4125 DCHECK(rd.Is64Bits() || is_uint32(immediate));
4126
4127 // If the operation is NOT, invert the operation and immediate.
4128 if ((op & NOT) == NOT) {
4129 op = static_cast<LogicalOp>(op & ~NOT);
4130 immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);
4131 }
4132
4133 unsigned n, imm_s, imm_r;
4134 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
4135 // Immediate can be encoded in the instruction.
4136 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
4137 } else {
4138 // This case is handled in the macro assembler.
4139 UNREACHABLE();
4140 }
4141 } else {
4142 DCHECK(operand.IsShiftedRegister());
4143 DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
4144 Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed);
4145 DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);
4146 }
4147 }
4148
4149
LogicalImmediate(const Register & rd,const Register & rn,unsigned n,unsigned imm_s,unsigned imm_r,LogicalOp op)4150 void Assembler::LogicalImmediate(const Register& rd,
4151 const Register& rn,
4152 unsigned n,
4153 unsigned imm_s,
4154 unsigned imm_r,
4155 LogicalOp op) {
4156 unsigned reg_size = rd.SizeInBits();
4157 Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);
4158 Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |
4159 ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |
4160 Rn(rn));
4161 }
4162
4163
ConditionalCompare(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)4164 void Assembler::ConditionalCompare(const Register& rn,
4165 const Operand& operand,
4166 StatusFlags nzcv,
4167 Condition cond,
4168 ConditionalCompareOp op) {
4169 Instr ccmpop;
4170 DCHECK(!operand.NeedsRelocation(this));
4171 if (operand.IsImmediate()) {
4172 int64_t immediate = operand.ImmediateValue();
4173 DCHECK(IsImmConditionalCompare(immediate));
4174 ccmpop = ConditionalCompareImmediateFixed | op |
4175 ImmCondCmp(static_cast<unsigned>(immediate));
4176 } else {
4177 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
4178 ccmpop = ConditionalCompareRegisterFixed | op | Rm(operand.reg());
4179 }
4180 Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));
4181 }
4182
4183
DataProcessing1Source(const Register & rd,const Register & rn,DataProcessing1SourceOp op)4184 void Assembler::DataProcessing1Source(const Register& rd,
4185 const Register& rn,
4186 DataProcessing1SourceOp op) {
4187 DCHECK(rd.SizeInBits() == rn.SizeInBits());
4188 Emit(SF(rn) | op | Rn(rn) | Rd(rd));
4189 }
4190
FPDataProcessing1Source(const VRegister & vd,const VRegister & vn,FPDataProcessing1SourceOp op)4191 void Assembler::FPDataProcessing1Source(const VRegister& vd,
4192 const VRegister& vn,
4193 FPDataProcessing1SourceOp op) {
4194 Emit(FPType(vn) | op | Rn(vn) | Rd(vd));
4195 }
4196
FPDataProcessing2Source(const VRegister & fd,const VRegister & fn,const VRegister & fm,FPDataProcessing2SourceOp op)4197 void Assembler::FPDataProcessing2Source(const VRegister& fd,
4198 const VRegister& fn,
4199 const VRegister& fm,
4200 FPDataProcessing2SourceOp op) {
4201 DCHECK(fd.SizeInBits() == fn.SizeInBits());
4202 DCHECK(fd.SizeInBits() == fm.SizeInBits());
4203 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd));
4204 }
4205
FPDataProcessing3Source(const VRegister & fd,const VRegister & fn,const VRegister & fm,const VRegister & fa,FPDataProcessing3SourceOp op)4206 void Assembler::FPDataProcessing3Source(const VRegister& fd,
4207 const VRegister& fn,
4208 const VRegister& fm,
4209 const VRegister& fa,
4210 FPDataProcessing3SourceOp op) {
4211 DCHECK(AreSameSizeAndType(fd, fn, fm, fa));
4212 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa));
4213 }
4214
NEONModifiedImmShiftLsl(const VRegister & vd,const int imm8,const int left_shift,NEONModifiedImmediateOp op)4215 void Assembler::NEONModifiedImmShiftLsl(const VRegister& vd, const int imm8,
4216 const int left_shift,
4217 NEONModifiedImmediateOp op) {
4218 DCHECK(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H() || vd.Is2S() ||
4219 vd.Is4S());
4220 DCHECK((left_shift == 0) || (left_shift == 8) || (left_shift == 16) ||
4221 (left_shift == 24));
4222 DCHECK(is_uint8(imm8));
4223
4224 int cmode_1, cmode_2, cmode_3;
4225 if (vd.Is8B() || vd.Is16B()) {
4226 DCHECK_EQ(op, NEONModifiedImmediate_MOVI);
4227 cmode_1 = 1;
4228 cmode_2 = 1;
4229 cmode_3 = 1;
4230 } else {
4231 cmode_1 = (left_shift >> 3) & 1;
4232 cmode_2 = left_shift >> 4;
4233 cmode_3 = 0;
4234 if (vd.Is4H() || vd.Is8H()) {
4235 DCHECK((left_shift == 0) || (left_shift == 8));
4236 cmode_3 = 1;
4237 }
4238 }
4239 int cmode = (cmode_3 << 3) | (cmode_2 << 2) | (cmode_1 << 1);
4240
4241 Instr q = vd.IsQ() ? NEON_Q : 0;
4242
4243 Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));
4244 }
4245
NEONModifiedImmShiftMsl(const VRegister & vd,const int imm8,const int shift_amount,NEONModifiedImmediateOp op)4246 void Assembler::NEONModifiedImmShiftMsl(const VRegister& vd, const int imm8,
4247 const int shift_amount,
4248 NEONModifiedImmediateOp op) {
4249 DCHECK(vd.Is2S() || vd.Is4S());
4250 DCHECK((shift_amount == 8) || (shift_amount == 16));
4251 DCHECK(is_uint8(imm8));
4252
4253 int cmode_0 = (shift_amount >> 4) & 1;
4254 int cmode = 0xC | cmode_0;
4255
4256 Instr q = vd.IsQ() ? NEON_Q : 0;
4257
4258 Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));
4259 }
4260
EmitShift(const Register & rd,const Register & rn,Shift shift,unsigned shift_amount)4261 void Assembler::EmitShift(const Register& rd,
4262 const Register& rn,
4263 Shift shift,
4264 unsigned shift_amount) {
4265 switch (shift) {
4266 case LSL:
4267 lsl(rd, rn, shift_amount);
4268 break;
4269 case LSR:
4270 lsr(rd, rn, shift_amount);
4271 break;
4272 case ASR:
4273 asr(rd, rn, shift_amount);
4274 break;
4275 case ROR:
4276 ror(rd, rn, shift_amount);
4277 break;
4278 default:
4279 UNREACHABLE();
4280 }
4281 }
4282
4283
EmitExtendShift(const Register & rd,const Register & rn,Extend extend,unsigned left_shift)4284 void Assembler::EmitExtendShift(const Register& rd,
4285 const Register& rn,
4286 Extend extend,
4287 unsigned left_shift) {
4288 DCHECK(rd.SizeInBits() >= rn.SizeInBits());
4289 unsigned reg_size = rd.SizeInBits();
4290 // Use the correct size of register.
4291 Register rn_ = Register::Create(rn.code(), rd.SizeInBits());
4292 // Bits extracted are high_bit:0.
4293 unsigned high_bit = (8 << (extend & 0x3)) - 1;
4294 // Number of bits left in the result that are not introduced by the shift.
4295 unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);
4296
4297 if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {
4298 switch (extend) {
4299 case UXTB:
4300 case UXTH:
4301 case UXTW: ubfm(rd, rn_, non_shift_bits, high_bit); break;
4302 case SXTB:
4303 case SXTH:
4304 case SXTW: sbfm(rd, rn_, non_shift_bits, high_bit); break;
4305 case UXTX:
4306 case SXTX: {
4307 DCHECK_EQ(rn.SizeInBits(), kXRegSizeInBits);
4308 // Nothing to extend. Just shift.
4309 lsl(rd, rn_, left_shift);
4310 break;
4311 }
4312 default: UNREACHABLE();
4313 }
4314 } else {
4315 // No need to extend as the extended bits would be shifted away.
4316 lsl(rd, rn_, left_shift);
4317 }
4318 }
4319
4320
DataProcShiftedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)4321 void Assembler::DataProcShiftedRegister(const Register& rd,
4322 const Register& rn,
4323 const Operand& operand,
4324 FlagsUpdate S,
4325 Instr op) {
4326 DCHECK(operand.IsShiftedRegister());
4327 DCHECK(rn.Is64Bits() || (rn.Is32Bits() && is_uint5(operand.shift_amount())));
4328 DCHECK(!operand.NeedsRelocation(this));
4329 Emit(SF(rd) | op | Flags(S) |
4330 ShiftDP(operand.shift()) | ImmDPShift(operand.shift_amount()) |
4331 Rm(operand.reg()) | Rn(rn) | Rd(rd));
4332 }
4333
4334
DataProcExtendedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)4335 void Assembler::DataProcExtendedRegister(const Register& rd,
4336 const Register& rn,
4337 const Operand& operand,
4338 FlagsUpdate S,
4339 Instr op) {
4340 DCHECK(!operand.NeedsRelocation(this));
4341 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
4342 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) |
4343 ExtendMode(operand.extend()) | ImmExtendShift(operand.shift_amount()) |
4344 dest_reg | RnSP(rn));
4345 }
4346
4347
IsImmAddSub(int64_t immediate)4348 bool Assembler::IsImmAddSub(int64_t immediate) {
4349 return is_uint12(immediate) ||
4350 (is_uint12(immediate >> 12) && ((immediate & 0xFFF) == 0));
4351 }
4352
LoadStore(const CPURegister & rt,const MemOperand & addr,LoadStoreOp op)4353 void Assembler::LoadStore(const CPURegister& rt,
4354 const MemOperand& addr,
4355 LoadStoreOp op) {
4356 Instr memop = op | Rt(rt) | RnSP(addr.base());
4357
4358 if (addr.IsImmediateOffset()) {
4359 unsigned size = CalcLSDataSize(op);
4360 if (IsImmLSScaled(addr.offset(), size)) {
4361 int offset = static_cast<int>(addr.offset());
4362 // Use the scaled addressing mode.
4363 Emit(LoadStoreUnsignedOffsetFixed | memop |
4364 ImmLSUnsigned(offset >> size));
4365 } else if (IsImmLSUnscaled(addr.offset())) {
4366 int offset = static_cast<int>(addr.offset());
4367 // Use the unscaled addressing mode.
4368 Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset));
4369 } else {
4370 // This case is handled in the macro assembler.
4371 UNREACHABLE();
4372 }
4373 } else if (addr.IsRegisterOffset()) {
4374 Extend ext = addr.extend();
4375 Shift shift = addr.shift();
4376 unsigned shift_amount = addr.shift_amount();
4377
4378 // LSL is encoded in the option field as UXTX.
4379 if (shift == LSL) {
4380 ext = UXTX;
4381 }
4382
4383 // Shifts are encoded in one bit, indicating a left shift by the memory
4384 // access size.
4385 DCHECK((shift_amount == 0) ||
4386 (shift_amount == static_cast<unsigned>(CalcLSDataSize(op))));
4387 Emit(LoadStoreRegisterOffsetFixed | memop | Rm(addr.regoffset()) |
4388 ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0));
4389 } else {
4390 // Pre-index and post-index modes.
4391 DCHECK(!rt.Is(addr.base()));
4392 if (IsImmLSUnscaled(addr.offset())) {
4393 int offset = static_cast<int>(addr.offset());
4394 if (addr.IsPreIndex()) {
4395 Emit(LoadStorePreIndexFixed | memop | ImmLS(offset));
4396 } else {
4397 DCHECK(addr.IsPostIndex());
4398 Emit(LoadStorePostIndexFixed | memop | ImmLS(offset));
4399 }
4400 } else {
4401 // This case is handled in the macro assembler.
4402 UNREACHABLE();
4403 }
4404 }
4405 }
4406
4407
IsImmLSUnscaled(int64_t offset)4408 bool Assembler::IsImmLSUnscaled(int64_t offset) {
4409 return is_int9(offset);
4410 }
4411
IsImmLSScaled(int64_t offset,unsigned size)4412 bool Assembler::IsImmLSScaled(int64_t offset, unsigned size) {
4413 bool offset_is_size_multiple = (((offset >> size) << size) == offset);
4414 return offset_is_size_multiple && is_uint12(offset >> size);
4415 }
4416
IsImmLSPair(int64_t offset,unsigned size)4417 bool Assembler::IsImmLSPair(int64_t offset, unsigned size) {
4418 bool offset_is_size_multiple = (((offset >> size) << size) == offset);
4419 return offset_is_size_multiple && is_int7(offset >> size);
4420 }
4421
4422
IsImmLLiteral(int64_t offset)4423 bool Assembler::IsImmLLiteral(int64_t offset) {
4424 int inst_size = static_cast<int>(kInstrSizeLog2);
4425 bool offset_is_inst_multiple =
4426 (((offset >> inst_size) << inst_size) == offset);
4427 DCHECK_GT(offset, 0);
4428 offset >>= kLoadLiteralScaleLog2;
4429 return offset_is_inst_multiple && is_intn(offset, ImmLLiteral_width);
4430 }
4431
4432
4433 // Test if a given value can be encoded in the immediate field of a logical
4434 // instruction.
4435 // If it can be encoded, the function returns true, and values pointed to by n,
4436 // imm_s and imm_r are updated with immediates encoded in the format required
4437 // by the corresponding fields in the logical instruction.
4438 // If it can not be encoded, the function returns false, and the values pointed
4439 // to by n, imm_s and imm_r are undefined.
IsImmLogical(uint64_t value,unsigned width,unsigned * n,unsigned * imm_s,unsigned * imm_r)4440 bool Assembler::IsImmLogical(uint64_t value,
4441 unsigned width,
4442 unsigned* n,
4443 unsigned* imm_s,
4444 unsigned* imm_r) {
4445 DCHECK((n != nullptr) && (imm_s != nullptr) && (imm_r != nullptr));
4446 DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
4447
4448 bool negate = false;
4449
4450 // Logical immediates are encoded using parameters n, imm_s and imm_r using
4451 // the following table:
4452 //
4453 // N imms immr size S R
4454 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
4455 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
4456 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
4457 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
4458 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
4459 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
4460 // (s bits must not be all set)
4461 //
4462 // A pattern is constructed of size bits, where the least significant S+1 bits
4463 // are set. The pattern is rotated right by R, and repeated across a 32 or
4464 // 64-bit value, depending on destination register width.
4465 //
4466 // Put another way: the basic format of a logical immediate is a single
4467 // contiguous stretch of 1 bits, repeated across the whole word at intervals
4468 // given by a power of 2. To identify them quickly, we first locate the
4469 // lowest stretch of 1 bits, then the next 1 bit above that; that combination
4470 // is different for every logical immediate, so it gives us all the
4471 // information we need to identify the only logical immediate that our input
4472 // could be, and then we simply check if that's the value we actually have.
4473 //
4474 // (The rotation parameter does give the possibility of the stretch of 1 bits
4475 // going 'round the end' of the word. To deal with that, we observe that in
4476 // any situation where that happens the bitwise NOT of the value is also a
4477 // valid logical immediate. So we simply invert the input whenever its low bit
4478 // is set, and then we know that the rotated case can't arise.)
4479
4480 if (value & 1) {
4481 // If the low bit is 1, negate the value, and set a flag to remember that we
4482 // did (so that we can adjust the return values appropriately).
4483 negate = true;
4484 value = ~value;
4485 }
4486
4487 if (width == kWRegSizeInBits) {
4488 // To handle 32-bit logical immediates, the very easiest thing is to repeat
4489 // the input value twice to make a 64-bit word. The correct encoding of that
4490 // as a logical immediate will also be the correct encoding of the 32-bit
4491 // value.
4492
4493 // The most-significant 32 bits may not be zero (ie. negate is true) so
4494 // shift the value left before duplicating it.
4495 value <<= kWRegSizeInBits;
4496 value |= value >> kWRegSizeInBits;
4497 }
4498
4499 // The basic analysis idea: imagine our input word looks like this.
4500 //
4501 // 0011111000111110001111100011111000111110001111100011111000111110
4502 // c b a
4503 // |<--d-->|
4504 //
4505 // We find the lowest set bit (as an actual power-of-2 value, not its index)
4506 // and call it a. Then we add a to our original number, which wipes out the
4507 // bottommost stretch of set bits and replaces it with a 1 carried into the
4508 // next zero bit. Then we look for the new lowest set bit, which is in
4509 // position b, and subtract it, so now our number is just like the original
4510 // but with the lowest stretch of set bits completely gone. Now we find the
4511 // lowest set bit again, which is position c in the diagram above. Then we'll
4512 // measure the distance d between bit positions a and c (using CLZ), and that
4513 // tells us that the only valid logical immediate that could possibly be equal
4514 // to this number is the one in which a stretch of bits running from a to just
4515 // below b is replicated every d bits.
4516 uint64_t a = LargestPowerOf2Divisor(value);
4517 uint64_t value_plus_a = value + a;
4518 uint64_t b = LargestPowerOf2Divisor(value_plus_a);
4519 uint64_t value_plus_a_minus_b = value_plus_a - b;
4520 uint64_t c = LargestPowerOf2Divisor(value_plus_a_minus_b);
4521
4522 int d, clz_a, out_n;
4523 uint64_t mask;
4524
4525 if (c != 0) {
4526 // The general case, in which there is more than one stretch of set bits.
4527 // Compute the repeat distance d, and set up a bitmask covering the basic
4528 // unit of repetition (i.e. a word with the bottom d bits set). Also, in all
4529 // of these cases the N bit of the output will be zero.
4530 clz_a = CountLeadingZeros(a, kXRegSizeInBits);
4531 int clz_c = CountLeadingZeros(c, kXRegSizeInBits);
4532 d = clz_a - clz_c;
4533 mask = ((uint64_t{1} << d) - 1);
4534 out_n = 0;
4535 } else {
4536 // Handle degenerate cases.
4537 //
4538 // If any of those 'find lowest set bit' operations didn't find a set bit at
4539 // all, then the word will have been zero thereafter, so in particular the
4540 // last lowest_set_bit operation will have returned zero. So we can test for
4541 // all the special case conditions in one go by seeing if c is zero.
4542 if (a == 0) {
4543 // The input was zero (or all 1 bits, which will come to here too after we
4544 // inverted it at the start of the function), for which we just return
4545 // false.
4546 return false;
4547 } else {
4548 // Otherwise, if c was zero but a was not, then there's just one stretch
4549 // of set bits in our word, meaning that we have the trivial case of
4550 // d == 64 and only one 'repetition'. Set up all the same variables as in
4551 // the general case above, and set the N bit in the output.
4552 clz_a = CountLeadingZeros(a, kXRegSizeInBits);
4553 d = 64;
4554 mask = ~uint64_t{0};
4555 out_n = 1;
4556 }
4557 }
4558
4559 // If the repeat period d is not a power of two, it can't be encoded.
4560 if (!base::bits::IsPowerOfTwo(d)) {
4561 return false;
4562 }
4563
4564 if (((b - a) & ~mask) != 0) {
4565 // If the bit stretch (b - a) does not fit within the mask derived from the
4566 // repeat period, then fail.
4567 return false;
4568 }
4569
4570 // The only possible option is b - a repeated every d bits. Now we're going to
4571 // actually construct the valid logical immediate derived from that
4572 // specification, and see if it equals our original input.
4573 //
4574 // To repeat a value every d bits, we multiply it by a number of the form
4575 // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
4576 // be derived using a table lookup on CLZ(d).
4577 static const uint64_t multipliers[] = {
4578 0x0000000000000001UL,
4579 0x0000000100000001UL,
4580 0x0001000100010001UL,
4581 0x0101010101010101UL,
4582 0x1111111111111111UL,
4583 0x5555555555555555UL,
4584 };
4585 int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57;
4586 // Ensure that the index to the multipliers array is within bounds.
4587 DCHECK((multiplier_idx >= 0) &&
4588 (static_cast<size_t>(multiplier_idx) < arraysize(multipliers)));
4589 uint64_t multiplier = multipliers[multiplier_idx];
4590 uint64_t candidate = (b - a) * multiplier;
4591
4592 if (value != candidate) {
4593 // The candidate pattern doesn't match our input value, so fail.
4594 return false;
4595 }
4596
4597 // We have a match! This is a valid logical immediate, so now we have to
4598 // construct the bits and pieces of the instruction encoding that generates
4599 // it.
4600
4601 // Count the set bits in our basic stretch. The special case of clz(0) == -1
4602 // makes the answer come out right for stretches that reach the very top of
4603 // the word (e.g. numbers like 0xFFFFC00000000000).
4604 int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSizeInBits);
4605 int s = clz_a - clz_b;
4606
4607 // Decide how many bits to rotate right by, to put the low bit of that basic
4608 // stretch in position a.
4609 int r;
4610 if (negate) {
4611 // If we inverted the input right at the start of this function, here's
4612 // where we compensate: the number of set bits becomes the number of clear
4613 // bits, and the rotation count is based on position b rather than position
4614 // a (since b is the location of the 'lowest' 1 bit after inversion).
4615 s = d - s;
4616 r = (clz_b + 1) & (d - 1);
4617 } else {
4618 r = (clz_a + 1) & (d - 1);
4619 }
4620
4621 // Now we're done, except for having to encode the S output in such a way that
4622 // it gives both the number of set bits and the length of the repeated
4623 // segment. The s field is encoded like this:
4624 //
4625 // imms size S
4626 // ssssss 64 UInt(ssssss)
4627 // 0sssss 32 UInt(sssss)
4628 // 10ssss 16 UInt(ssss)
4629 // 110sss 8 UInt(sss)
4630 // 1110ss 4 UInt(ss)
4631 // 11110s 2 UInt(s)
4632 //
4633 // So we 'or' (-d << 1) with our computed s to form imms.
4634 *n = out_n;
4635 *imm_s = ((-d << 1) | (s - 1)) & 0x3F;
4636 *imm_r = r;
4637
4638 return true;
4639 }
4640
4641
IsImmConditionalCompare(int64_t immediate)4642 bool Assembler::IsImmConditionalCompare(int64_t immediate) {
4643 return is_uint5(immediate);
4644 }
4645
4646
IsImmFP32(float imm)4647 bool Assembler::IsImmFP32(float imm) {
4648 // Valid values will have the form:
4649 // aBbb.bbbc.defg.h000.0000.0000.0000.0000
4650 uint32_t bits = bit_cast<uint32_t>(imm);
4651 // bits[19..0] are cleared.
4652 if ((bits & 0x7FFFF) != 0) {
4653 return false;
4654 }
4655
4656 // bits[29..25] are all set or all cleared.
4657 uint32_t b_pattern = (bits >> 16) & 0x3E00;
4658 if (b_pattern != 0 && b_pattern != 0x3E00) {
4659 return false;
4660 }
4661
4662 // bit[30] and bit[29] are opposite.
4663 if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
4664 return false;
4665 }
4666
4667 return true;
4668 }
4669
4670
IsImmFP64(double imm)4671 bool Assembler::IsImmFP64(double imm) {
4672 // Valid values will have the form:
4673 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
4674 // 0000.0000.0000.0000.0000.0000.0000.0000
4675 uint64_t bits = bit_cast<uint64_t>(imm);
4676 // bits[47..0] are cleared.
4677 if ((bits & 0xFFFFFFFFFFFFL) != 0) {
4678 return false;
4679 }
4680
4681 // bits[61..54] are all set or all cleared.
4682 uint32_t b_pattern = (bits >> 48) & 0x3FC0;
4683 if (b_pattern != 0 && b_pattern != 0x3FC0) {
4684 return false;
4685 }
4686
4687 // bit[62] and bit[61] are opposite.
4688 if (((bits ^ (bits << 1)) & 0x4000000000000000L) == 0) {
4689 return false;
4690 }
4691
4692 return true;
4693 }
4694
4695
GrowBuffer()4696 void Assembler::GrowBuffer() {
4697 if (!own_buffer_) FATAL("external code buffer is too small");
4698
4699 // Compute new buffer size.
4700 CodeDesc desc; // the new buffer
4701 if (buffer_size_ < 1 * MB) {
4702 desc.buffer_size = 2 * buffer_size_;
4703 } else {
4704 desc.buffer_size = buffer_size_ + 1 * MB;
4705 }
4706
4707 // Some internal data structures overflow for very large buffers,
4708 // they must ensure that kMaximalBufferSize is not too large.
4709 if (desc.buffer_size > kMaximalBufferSize) {
4710 V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
4711 }
4712
4713 byte* buffer = reinterpret_cast<byte*>(buffer_);
4714
4715 // Set up new buffer.
4716 desc.buffer = NewArray<byte>(desc.buffer_size);
4717 desc.origin = this;
4718
4719 desc.instr_size = pc_offset();
4720 desc.reloc_size =
4721 static_cast<int>((buffer + buffer_size_) - reloc_info_writer.pos());
4722
4723 // Copy the data.
4724 intptr_t pc_delta = desc.buffer - buffer;
4725 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
4726 (buffer + buffer_size_);
4727 memmove(desc.buffer, buffer, desc.instr_size);
4728 memmove(reloc_info_writer.pos() + rc_delta,
4729 reloc_info_writer.pos(), desc.reloc_size);
4730
4731 // Switch buffers.
4732 DeleteArray(buffer_);
4733 buffer_ = desc.buffer;
4734 buffer_size_ = desc.buffer_size;
4735 pc_ = pc_ + pc_delta;
4736 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
4737 reloc_info_writer.last_pc() + pc_delta);
4738
4739 // None of our relocation types are pc relative pointing outside the code
4740 // buffer nor pc absolute pointing inside the code buffer, so there is no need
4741 // to relocate any emitted relocation entries.
4742
4743 // Relocate internal references.
4744 for (auto pos : internal_reference_positions_) {
4745 intptr_t* p = reinterpret_cast<intptr_t*>(buffer_ + pos);
4746 *p += pc_delta;
4747 }
4748
4749 // Pending relocation entries are also relative, no need to relocate.
4750 }
4751
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data,ConstantPoolMode constant_pool_mode)4752 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data,
4753 ConstantPoolMode constant_pool_mode) {
4754 // Non-relocatable constants should not end up in the literal pool.
4755 DCHECK(!RelocInfo::IsNone(rmode));
4756 if (options().disable_reloc_info_for_patching) return;
4757
4758 // We do not try to reuse pool constants.
4759 RelocInfo rinfo(reinterpret_cast<Address>(pc_), rmode, data, nullptr);
4760 bool write_reloc_info = true;
4761
4762 if ((rmode == RelocInfo::COMMENT) ||
4763 (rmode == RelocInfo::INTERNAL_REFERENCE) ||
4764 (rmode == RelocInfo::CONST_POOL) || (rmode == RelocInfo::VENEER_POOL) ||
4765 (rmode == RelocInfo::DEOPT_SCRIPT_OFFSET) ||
4766 (rmode == RelocInfo::DEOPT_INLINING_ID) ||
4767 (rmode == RelocInfo::DEOPT_REASON) || (rmode == RelocInfo::DEOPT_ID)) {
4768 // Adjust code for new modes.
4769 DCHECK(RelocInfo::IsComment(rmode) || RelocInfo::IsDeoptReason(rmode) ||
4770 RelocInfo::IsDeoptId(rmode) || RelocInfo::IsDeoptPosition(rmode) ||
4771 RelocInfo::IsInternalReference(rmode) ||
4772 RelocInfo::IsConstPool(rmode) || RelocInfo::IsVeneerPool(rmode));
4773 // These modes do not need an entry in the constant pool.
4774 } else if (constant_pool_mode == NEEDS_POOL_ENTRY) {
4775 write_reloc_info = constpool_.RecordEntry(data, rmode);
4776 // Make sure the constant pool is not emitted in place of the next
4777 // instruction for which we just recorded relocation info.
4778 BlockConstPoolFor(1);
4779 }
4780 // For modes that cannot use the constant pool, a different sequence of
4781 // instructions will be emitted by this function's caller.
4782
4783 if (write_reloc_info) {
4784 // Don't record external references unless the heap will be serialized.
4785 if (RelocInfo::IsOnlyForSerializer(rmode) &&
4786 !options().record_reloc_info_for_serialization && !emit_debug_code()) {
4787 return;
4788 }
4789 DCHECK_GE(buffer_space(), kMaxRelocSize); // too late to grow buffer here
4790 reloc_info_writer.Write(&rinfo);
4791 }
4792 }
4793
near_jump(int offset,RelocInfo::Mode rmode)4794 void Assembler::near_jump(int offset, RelocInfo::Mode rmode) {
4795 if (!RelocInfo::IsNone(rmode)) RecordRelocInfo(rmode, offset, NO_POOL_ENTRY);
4796 b(offset);
4797 }
4798
near_call(int offset,RelocInfo::Mode rmode)4799 void Assembler::near_call(int offset, RelocInfo::Mode rmode) {
4800 if (!RelocInfo::IsNone(rmode)) RecordRelocInfo(rmode, offset, NO_POOL_ENTRY);
4801 bl(offset);
4802 }
4803
near_call(HeapObjectRequest request)4804 void Assembler::near_call(HeapObjectRequest request) {
4805 RequestHeapObject(request);
4806 int index = AddCodeTarget(Handle<Code>());
4807 RecordRelocInfo(RelocInfo::CODE_TARGET, index, NO_POOL_ENTRY);
4808 bl(index);
4809 }
4810
BlockConstPoolFor(int instructions)4811 void Assembler::BlockConstPoolFor(int instructions) {
4812 int pc_limit = pc_offset() + instructions * kInstrSize;
4813 if (no_const_pool_before_ < pc_limit) {
4814 no_const_pool_before_ = pc_limit;
4815 // Make sure the pool won't be blocked for too long.
4816 DCHECK(pc_limit < constpool_.MaxPcOffset());
4817 }
4818
4819 if (next_constant_pool_check_ < no_const_pool_before_) {
4820 next_constant_pool_check_ = no_const_pool_before_;
4821 }
4822 }
4823
4824
CheckConstPool(bool force_emit,bool require_jump)4825 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
4826 // Some short sequence of instruction mustn't be broken up by constant pool
4827 // emission, such sequences are protected by calls to BlockConstPoolFor and
4828 // BlockConstPoolScope.
4829 if (is_const_pool_blocked()) {
4830 // Something is wrong if emission is forced and blocked at the same time.
4831 DCHECK(!force_emit);
4832 return;
4833 }
4834
4835 // There is nothing to do if there are no pending constant pool entries.
4836 if (constpool_.IsEmpty()) {
4837 // Calculate the offset of the next check.
4838 SetNextConstPoolCheckIn(kCheckConstPoolInterval);
4839 return;
4840 }
4841
4842 // We emit a constant pool when:
4843 // * requested to do so by parameter force_emit (e.g. after each function).
4844 // * the distance to the first instruction accessing the constant pool is
4845 // kApproxMaxDistToConstPool or more.
4846 // * the number of entries in the pool is kApproxMaxPoolEntryCount or more.
4847 int dist = constpool_.DistanceToFirstUse();
4848 int count = constpool_.EntryCount();
4849 if (!force_emit &&
4850 (dist < kApproxMaxDistToConstPool) &&
4851 (count < kApproxMaxPoolEntryCount)) {
4852 return;
4853 }
4854
4855
4856 // Emit veneers for branches that would go out of range during emission of the
4857 // constant pool.
4858 int worst_case_size = constpool_.WorstCaseSize();
4859 CheckVeneerPool(false, require_jump,
4860 kVeneerDistanceMargin + worst_case_size);
4861
4862 // Check that the code buffer is large enough before emitting the constant
4863 // pool (this includes the gap to the relocation information).
4864 int needed_space = worst_case_size + kGap + 1 * kInstrSize;
4865 while (buffer_space() <= needed_space) {
4866 GrowBuffer();
4867 }
4868
4869 Label size_check;
4870 bind(&size_check);
4871 constpool_.Emit(require_jump);
4872 DCHECK(SizeOfCodeGeneratedSince(&size_check) <=
4873 static_cast<unsigned>(worst_case_size));
4874
4875 // Since a constant pool was just emitted, move the check offset forward by
4876 // the standard interval.
4877 SetNextConstPoolCheckIn(kCheckConstPoolInterval);
4878 }
4879
4880
ShouldEmitVeneer(int max_reachable_pc,int margin)4881 bool Assembler::ShouldEmitVeneer(int max_reachable_pc, int margin) {
4882 // Account for the branch around the veneers and the guard.
4883 int protection_offset = 2 * kInstrSize;
4884 return pc_offset() > max_reachable_pc - margin - protection_offset -
4885 static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize);
4886 }
4887
4888
RecordVeneerPool(int location_offset,int size)4889 void Assembler::RecordVeneerPool(int location_offset, int size) {
4890 RelocInfo rinfo(reinterpret_cast<Address>(buffer_) + location_offset,
4891 RelocInfo::VENEER_POOL, static_cast<intptr_t>(size), nullptr);
4892 reloc_info_writer.Write(&rinfo);
4893 }
4894
4895
EmitVeneers(bool force_emit,bool need_protection,int margin)4896 void Assembler::EmitVeneers(bool force_emit, bool need_protection, int margin) {
4897 BlockPoolsScope scope(this);
4898 RecordComment("[ Veneers");
4899
4900 // The exact size of the veneer pool must be recorded (see the comment at the
4901 // declaration site of RecordConstPool()), but computing the number of
4902 // veneers that will be generated is not obvious. So instead we remember the
4903 // current position and will record the size after the pool has been
4904 // generated.
4905 Label size_check;
4906 bind(&size_check);
4907 int veneer_pool_relocinfo_loc = pc_offset();
4908
4909 Label end;
4910 if (need_protection) {
4911 b(&end);
4912 }
4913
4914 EmitVeneersGuard();
4915
4916 Label veneer_size_check;
4917
4918 std::multimap<int, FarBranchInfo>::iterator it, it_to_delete;
4919
4920 it = unresolved_branches_.begin();
4921 while (it != unresolved_branches_.end()) {
4922 if (force_emit || ShouldEmitVeneer(it->first, margin)) {
4923 Instruction* branch = InstructionAt(it->second.pc_offset_);
4924 Label* label = it->second.label_;
4925
4926 #ifdef DEBUG
4927 bind(&veneer_size_check);
4928 #endif
4929 // Patch the branch to point to the current position, and emit a branch
4930 // to the label.
4931 Instruction* veneer = reinterpret_cast<Instruction*>(pc_);
4932 RemoveBranchFromLabelLinkChain(branch, label, veneer);
4933 branch->SetImmPCOffsetTarget(options(), veneer);
4934 b(label);
4935 #ifdef DEBUG
4936 DCHECK(SizeOfCodeGeneratedSince(&veneer_size_check) <=
4937 static_cast<uint64_t>(kMaxVeneerCodeSize));
4938 veneer_size_check.Unuse();
4939 #endif
4940
4941 it_to_delete = it++;
4942 unresolved_branches_.erase(it_to_delete);
4943 } else {
4944 ++it;
4945 }
4946 }
4947
4948 // Record the veneer pool size.
4949 int pool_size = static_cast<int>(SizeOfCodeGeneratedSince(&size_check));
4950 RecordVeneerPool(veneer_pool_relocinfo_loc, pool_size);
4951
4952 if (unresolved_branches_.empty()) {
4953 next_veneer_pool_check_ = kMaxInt;
4954 } else {
4955 next_veneer_pool_check_ =
4956 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
4957 }
4958
4959 bind(&end);
4960
4961 RecordComment("]");
4962 }
4963
4964
CheckVeneerPool(bool force_emit,bool require_jump,int margin)4965 void Assembler::CheckVeneerPool(bool force_emit, bool require_jump,
4966 int margin) {
4967 // There is nothing to do if there are no pending veneer pool entries.
4968 if (unresolved_branches_.empty()) {
4969 DCHECK_EQ(next_veneer_pool_check_, kMaxInt);
4970 return;
4971 }
4972
4973 DCHECK(pc_offset() < unresolved_branches_first_limit());
4974
4975 // Some short sequence of instruction mustn't be broken up by veneer pool
4976 // emission, such sequences are protected by calls to BlockVeneerPoolFor and
4977 // BlockVeneerPoolScope.
4978 if (is_veneer_pool_blocked()) {
4979 DCHECK(!force_emit);
4980 return;
4981 }
4982
4983 if (!require_jump) {
4984 // Prefer emitting veneers protected by an existing instruction.
4985 margin *= kVeneerNoProtectionFactor;
4986 }
4987 if (force_emit || ShouldEmitVeneers(margin)) {
4988 EmitVeneers(force_emit, require_jump, margin);
4989 } else {
4990 next_veneer_pool_check_ =
4991 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
4992 }
4993 }
4994
4995
buffer_space() const4996 int Assembler::buffer_space() const {
4997 return static_cast<int>(reloc_info_writer.pos() - pc_);
4998 }
4999
5000
RecordConstPool(int size)5001 void Assembler::RecordConstPool(int size) {
5002 // We only need this for debugger support, to correctly compute offsets in the
5003 // code.
5004 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
5005 }
5006
5007
PatchAdrFar(int64_t target_offset)5008 void PatchingAssembler::PatchAdrFar(int64_t target_offset) {
5009 // The code at the current instruction should be:
5010 // adr rd, 0
5011 // nop (adr_far)
5012 // nop (adr_far)
5013 // movz scratch, 0
5014
5015 // Verify the expected code.
5016 Instruction* expected_adr = InstructionAt(0);
5017 CHECK(expected_adr->IsAdr() && (expected_adr->ImmPCRel() == 0));
5018 int rd_code = expected_adr->Rd();
5019 for (int i = 0; i < kAdrFarPatchableNNops; ++i) {
5020 CHECK(InstructionAt((i + 1) * kInstrSize)->IsNop(ADR_FAR_NOP));
5021 }
5022 Instruction* expected_movz =
5023 InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstrSize);
5024 CHECK(expected_movz->IsMovz() &&
5025 (expected_movz->ImmMoveWide() == 0) &&
5026 (expected_movz->ShiftMoveWide() == 0));
5027 int scratch_code = expected_movz->Rd();
5028
5029 // Patch to load the correct address.
5030 Register rd = Register::XRegFromCode(rd_code);
5031 Register scratch = Register::XRegFromCode(scratch_code);
5032 // Addresses are only 48 bits.
5033 adr(rd, target_offset & 0xFFFF);
5034 movz(scratch, (target_offset >> 16) & 0xFFFF, 16);
5035 movk(scratch, (target_offset >> 32) & 0xFFFF, 32);
5036 DCHECK_EQ(target_offset >> 48, 0);
5037 add(rd, rd, scratch);
5038 }
5039
PatchSubSp(uint32_t immediate)5040 void PatchingAssembler::PatchSubSp(uint32_t immediate) {
5041 // The code at the current instruction should be:
5042 // sub sp, sp, #0
5043
5044 // Verify the expected code.
5045 Instruction* expected_adr = InstructionAt(0);
5046 CHECK(expected_adr->IsAddSubImmediate());
5047 sub(sp, sp, immediate);
5048 }
5049
5050 } // namespace internal
5051 } // namespace v8
5052
5053 #endif // V8_TARGET_ARCH_ARM64
5054