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