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 #define ARM64_DEFINE_REG_STATICS
32 #include "src/arm64/assembler-arm64.h"
33
34 #include "src/arm64/assembler-arm64-inl.h"
35 #include "src/arm64/frames-arm64.h"
36 #include "src/base/bits.h"
37 #include "src/base/cpu.h"
38 #include "src/register-configuration.h"
39
40 namespace v8 {
41 namespace internal {
42
43
44 // -----------------------------------------------------------------------------
45 // CpuFeatures implementation.
46
ProbeImpl(bool cross_compile)47 void CpuFeatures::ProbeImpl(bool cross_compile) {
48 // AArch64 has no configuration options, no further probing is required.
49 supported_ = 0;
50
51 // Only use statically determined features for cross compile (snapshot).
52 if (cross_compile) return;
53
54 // We used to probe for coherent cache support, but on older CPUs it
55 // causes crashes (crbug.com/524337), and newer CPUs don't even have
56 // the feature any more.
57 }
58
PrintTarget()59 void CpuFeatures::PrintTarget() { }
PrintFeatures()60 void CpuFeatures::PrintFeatures() {}
61
62 // -----------------------------------------------------------------------------
63 // CPURegList utilities.
64
PopLowestIndex()65 CPURegister CPURegList::PopLowestIndex() {
66 DCHECK(IsValid());
67 if (IsEmpty()) {
68 return NoCPUReg;
69 }
70 int index = CountTrailingZeros(list_, kRegListSizeInBits);
71 DCHECK((1 << index) & list_);
72 Remove(index);
73 return CPURegister::Create(index, size_, type_);
74 }
75
76
PopHighestIndex()77 CPURegister CPURegList::PopHighestIndex() {
78 DCHECK(IsValid());
79 if (IsEmpty()) {
80 return NoCPUReg;
81 }
82 int index = CountLeadingZeros(list_, kRegListSizeInBits);
83 index = kRegListSizeInBits - 1 - index;
84 DCHECK((1 << index) & list_);
85 Remove(index);
86 return CPURegister::Create(index, size_, type_);
87 }
88
89
RemoveCalleeSaved()90 void CPURegList::RemoveCalleeSaved() {
91 if (type() == CPURegister::kRegister) {
92 Remove(GetCalleeSaved(RegisterSizeInBits()));
93 } else if (type() == CPURegister::kFPRegister) {
94 Remove(GetCalleeSavedFP(RegisterSizeInBits()));
95 } else {
96 DCHECK(type() == CPURegister::kNoRegister);
97 DCHECK(IsEmpty());
98 // The list must already be empty, so do nothing.
99 }
100 }
101
102
GetCalleeSaved(int size)103 CPURegList CPURegList::GetCalleeSaved(int size) {
104 return CPURegList(CPURegister::kRegister, size, 19, 29);
105 }
106
107
GetCalleeSavedFP(int size)108 CPURegList CPURegList::GetCalleeSavedFP(int size) {
109 return CPURegList(CPURegister::kFPRegister, size, 8, 15);
110 }
111
112
GetCallerSaved(int size)113 CPURegList CPURegList::GetCallerSaved(int size) {
114 // Registers x0-x18 and lr (x30) are caller-saved.
115 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18);
116 list.Combine(lr);
117 return list;
118 }
119
120
GetCallerSavedFP(int size)121 CPURegList CPURegList::GetCallerSavedFP(int size) {
122 // Registers d0-d7 and d16-d31 are caller-saved.
123 CPURegList list = CPURegList(CPURegister::kFPRegister, size, 0, 7);
124 list.Combine(CPURegList(CPURegister::kFPRegister, size, 16, 31));
125 return list;
126 }
127
128
129 // This function defines the list of registers which are associated with a
130 // safepoint slot. Safepoint register slots are saved contiguously on the stack.
131 // MacroAssembler::SafepointRegisterStackIndex handles mapping from register
132 // code to index in the safepoint register slots. Any change here can affect
133 // this mapping.
GetSafepointSavedRegisters()134 CPURegList CPURegList::GetSafepointSavedRegisters() {
135 CPURegList list = CPURegList::GetCalleeSaved();
136 list.Combine(
137 CPURegList(CPURegister::kRegister, kXRegSizeInBits, kJSCallerSaved));
138
139 // Note that unfortunately we can't use symbolic names for registers and have
140 // to directly use register codes. This is because this function is used to
141 // initialize some static variables and we can't rely on register variables
142 // to be initialized due to static initialization order issues in C++.
143
144 // Drop ip0 and ip1 (i.e. x16 and x17), as they should not be expected to be
145 // preserved outside of the macro assembler.
146 list.Remove(16);
147 list.Remove(17);
148
149 // Add x18 to the safepoint list, as although it's not in kJSCallerSaved, it
150 // is a caller-saved register according to the procedure call standard.
151 list.Combine(18);
152
153 // Drop jssp as the stack pointer doesn't need to be included.
154 list.Remove(28);
155
156 // Add the link register (x30) to the safepoint list.
157 list.Combine(30);
158
159 return list;
160 }
161
162
163 // -----------------------------------------------------------------------------
164 // Implementation of RelocInfo
165
166 const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
167
168
IsCodedSpecially()169 bool RelocInfo::IsCodedSpecially() {
170 // The deserializer needs to know whether a pointer is specially coded. Being
171 // specially coded on ARM64 means that it is a movz/movk sequence. We don't
172 // generate those for relocatable pointers.
173 return false;
174 }
175
176
IsInConstantPool()177 bool RelocInfo::IsInConstantPool() {
178 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
179 return instr->IsLdrLiteralX();
180 }
181
wasm_memory_reference()182 Address RelocInfo::wasm_memory_reference() {
183 DCHECK(IsWasmMemoryReference(rmode_));
184 return Memory::Address_at(Assembler::target_pointer_address_at(pc_));
185 }
186
wasm_memory_size_reference()187 uint32_t RelocInfo::wasm_memory_size_reference() {
188 DCHECK(IsWasmMemorySizeReference(rmode_));
189 return Memory::uint32_at(Assembler::target_pointer_address_at(pc_));
190 }
191
wasm_global_reference()192 Address RelocInfo::wasm_global_reference() {
193 DCHECK(IsWasmGlobalReference(rmode_));
194 return Memory::Address_at(Assembler::target_pointer_address_at(pc_));
195 }
196
wasm_function_table_size_reference()197 uint32_t RelocInfo::wasm_function_table_size_reference() {
198 DCHECK(IsWasmFunctionTableSizeReference(rmode_));
199 return Memory::uint32_at(Assembler::target_pointer_address_at(pc_));
200 }
201
unchecked_update_wasm_memory_reference(Address address,ICacheFlushMode flush_mode)202 void RelocInfo::unchecked_update_wasm_memory_reference(
203 Address address, ICacheFlushMode flush_mode) {
204 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
205 }
206
unchecked_update_wasm_size(uint32_t size,ICacheFlushMode flush_mode)207 void RelocInfo::unchecked_update_wasm_size(uint32_t size,
208 ICacheFlushMode flush_mode) {
209 Memory::uint32_at(Assembler::target_pointer_address_at(pc_)) = size;
210 }
211
GetAllocatableRegisterThatIsNotOneOf(Register reg1,Register reg2,Register reg3,Register reg4)212 Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2,
213 Register reg3, Register reg4) {
214 CPURegList regs(reg1, reg2, reg3, reg4);
215 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
216 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
217 int code = config->GetAllocatableDoubleCode(i);
218 Register candidate = Register::from_code(code);
219 if (regs.IncludesAliasOf(candidate)) continue;
220 return candidate;
221 }
222 UNREACHABLE();
223 return NoReg;
224 }
225
226
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)227 bool AreAliased(const CPURegister& reg1, const CPURegister& reg2,
228 const CPURegister& reg3, const CPURegister& reg4,
229 const CPURegister& reg5, const CPURegister& reg6,
230 const CPURegister& reg7, const CPURegister& reg8) {
231 int number_of_valid_regs = 0;
232 int number_of_valid_fpregs = 0;
233
234 RegList unique_regs = 0;
235 RegList unique_fpregs = 0;
236
237 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
238
239 for (unsigned i = 0; i < arraysize(regs); i++) {
240 if (regs[i].IsRegister()) {
241 number_of_valid_regs++;
242 unique_regs |= regs[i].Bit();
243 } else if (regs[i].IsFPRegister()) {
244 number_of_valid_fpregs++;
245 unique_fpregs |= regs[i].Bit();
246 } else {
247 DCHECK(!regs[i].IsValid());
248 }
249 }
250
251 int number_of_unique_regs =
252 CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte);
253 int number_of_unique_fpregs =
254 CountSetBits(unique_fpregs, sizeof(unique_fpregs) * kBitsPerByte);
255
256 DCHECK(number_of_valid_regs >= number_of_unique_regs);
257 DCHECK(number_of_valid_fpregs >= number_of_unique_fpregs);
258
259 return (number_of_valid_regs != number_of_unique_regs) ||
260 (number_of_valid_fpregs != number_of_unique_fpregs);
261 }
262
263
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)264 bool AreSameSizeAndType(const CPURegister& reg1, const CPURegister& reg2,
265 const CPURegister& reg3, const CPURegister& reg4,
266 const CPURegister& reg5, const CPURegister& reg6,
267 const CPURegister& reg7, const CPURegister& reg8) {
268 DCHECK(reg1.IsValid());
269 bool match = true;
270 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
271 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
272 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
273 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
274 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
275 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
276 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
277 return match;
278 }
279
280
InitializeHandle(Handle<Object> handle)281 void Immediate::InitializeHandle(Handle<Object> handle) {
282 AllowDeferredHandleDereference using_raw_address;
283
284 // Verify all Objects referred by code are NOT in new space.
285 Object* obj = *handle;
286 if (obj->IsHeapObject()) {
287 value_ = reinterpret_cast<intptr_t>(handle.location());
288 rmode_ = RelocInfo::EMBEDDED_OBJECT;
289 } else {
290 STATIC_ASSERT(sizeof(intptr_t) == sizeof(int64_t));
291 value_ = reinterpret_cast<intptr_t>(obj);
292 rmode_ = RelocInfo::NONE64;
293 }
294 }
295
296
NeedsRelocation(const Assembler * assembler) const297 bool Operand::NeedsRelocation(const Assembler* assembler) const {
298 RelocInfo::Mode rmode = immediate_.rmode();
299
300 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
301 return assembler->serializer_enabled();
302 }
303
304 return !RelocInfo::IsNone(rmode);
305 }
306
307
308 // Constant Pool.
RecordEntry(intptr_t data,RelocInfo::Mode mode)309 void ConstPool::RecordEntry(intptr_t data,
310 RelocInfo::Mode mode) {
311 DCHECK(mode != RelocInfo::COMMENT && mode != RelocInfo::CONST_POOL &&
312 mode != RelocInfo::VENEER_POOL &&
313 mode != RelocInfo::CODE_AGE_SEQUENCE &&
314 mode != RelocInfo::DEOPT_SCRIPT_OFFSET &&
315 mode != RelocInfo::DEOPT_INLINING_ID &&
316 mode != RelocInfo::DEOPT_REASON && mode != RelocInfo::DEOPT_ID);
317 uint64_t raw_data = static_cast<uint64_t>(data);
318 int offset = assm_->pc_offset();
319 if (IsEmpty()) {
320 first_use_ = offset;
321 }
322
323 std::pair<uint64_t, int> entry = std::make_pair(raw_data, offset);
324 if (CanBeShared(mode)) {
325 shared_entries_.insert(entry);
326 if (shared_entries_.count(entry.first) == 1) {
327 shared_entries_count++;
328 }
329 } else {
330 unique_entries_.push_back(entry);
331 }
332
333 if (EntryCount() > Assembler::kApproxMaxPoolEntryCount) {
334 // Request constant pool emission after the next instruction.
335 assm_->SetNextConstPoolCheckIn(1);
336 }
337 }
338
339
DistanceToFirstUse()340 int ConstPool::DistanceToFirstUse() {
341 DCHECK(first_use_ >= 0);
342 return assm_->pc_offset() - first_use_;
343 }
344
345
MaxPcOffset()346 int ConstPool::MaxPcOffset() {
347 // There are no pending entries in the pool so we can never get out of
348 // range.
349 if (IsEmpty()) return kMaxInt;
350
351 // Entries are not necessarily emitted in the order they are added so in the
352 // worst case the first constant pool use will be accessing the last entry.
353 return first_use_ + kMaxLoadLiteralRange - WorstCaseSize();
354 }
355
356
WorstCaseSize()357 int ConstPool::WorstCaseSize() {
358 if (IsEmpty()) return 0;
359
360 // Max size prologue:
361 // b over
362 // ldr xzr, #pool_size
363 // blr xzr
364 // nop
365 // All entries are 64-bit for now.
366 return 4 * kInstructionSize + EntryCount() * kPointerSize;
367 }
368
369
SizeIfEmittedAtCurrentPc(bool require_jump)370 int ConstPool::SizeIfEmittedAtCurrentPc(bool require_jump) {
371 if (IsEmpty()) return 0;
372
373 // Prologue is:
374 // b over ;; if require_jump
375 // ldr xzr, #pool_size
376 // blr xzr
377 // nop ;; if not 64-bit aligned
378 int prologue_size = require_jump ? kInstructionSize : 0;
379 prologue_size += 2 * kInstructionSize;
380 prologue_size += IsAligned(assm_->pc_offset() + prologue_size, 8) ?
381 0 : kInstructionSize;
382
383 // All entries are 64-bit for now.
384 return prologue_size + EntryCount() * kPointerSize;
385 }
386
387
Emit(bool require_jump)388 void ConstPool::Emit(bool require_jump) {
389 DCHECK(!assm_->is_const_pool_blocked());
390 // Prevent recursive pool emission and protect from veneer pools.
391 Assembler::BlockPoolsScope block_pools(assm_);
392
393 int size = SizeIfEmittedAtCurrentPc(require_jump);
394 Label size_check;
395 assm_->bind(&size_check);
396
397 assm_->RecordConstPool(size);
398 // Emit the constant pool. It is preceded by an optional branch if
399 // require_jump and a header which will:
400 // 1) Encode the size of the constant pool, for use by the disassembler.
401 // 2) Terminate the program, to try to prevent execution from accidentally
402 // flowing into the constant pool.
403 // 3) align the pool entries to 64-bit.
404 // The header is therefore made of up to three arm64 instructions:
405 // ldr xzr, #<size of the constant pool in 32-bit words>
406 // blr xzr
407 // nop
408 //
409 // If executed, the header will likely segfault and lr will point to the
410 // instruction following the offending blr.
411 // TODO(all): Make the alignment part less fragile. Currently code is
412 // allocated as a byte array so there are no guarantees the alignment will
413 // be preserved on compaction. Currently it works as allocation seems to be
414 // 64-bit aligned.
415
416 // Emit branch if required
417 Label after_pool;
418 if (require_jump) {
419 assm_->b(&after_pool);
420 }
421
422 // Emit the header.
423 assm_->RecordComment("[ Constant Pool");
424 EmitMarker();
425 EmitGuard();
426 assm_->Align(8);
427
428 // Emit constant pool entries.
429 // TODO(all): currently each relocated constant is 64 bits, consider adding
430 // support for 32-bit entries.
431 EmitEntries();
432 assm_->RecordComment("]");
433
434 if (after_pool.is_linked()) {
435 assm_->bind(&after_pool);
436 }
437
438 DCHECK(assm_->SizeOfCodeGeneratedSince(&size_check) ==
439 static_cast<unsigned>(size));
440 }
441
442
Clear()443 void ConstPool::Clear() {
444 shared_entries_.clear();
445 shared_entries_count = 0;
446 unique_entries_.clear();
447 first_use_ = -1;
448 }
449
450
CanBeShared(RelocInfo::Mode mode)451 bool ConstPool::CanBeShared(RelocInfo::Mode mode) {
452 // Constant pool currently does not support 32-bit entries.
453 DCHECK(mode != RelocInfo::NONE32);
454
455 return RelocInfo::IsNone(mode) ||
456 (!assm_->serializer_enabled() &&
457 (mode >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE));
458 }
459
460
EmitMarker()461 void ConstPool::EmitMarker() {
462 // A constant pool size is expressed in number of 32-bits words.
463 // Currently all entries are 64-bit.
464 // + 1 is for the crash guard.
465 // + 0/1 for alignment.
466 int word_count = EntryCount() * 2 + 1 +
467 (IsAligned(assm_->pc_offset(), 8) ? 0 : 1);
468 assm_->Emit(LDR_x_lit |
469 Assembler::ImmLLiteral(word_count) |
470 Assembler::Rt(xzr));
471 }
472
473
AreConsistentForPair(const MemOperand & operandA,const MemOperand & operandB,int access_size_log2)474 MemOperand::PairResult MemOperand::AreConsistentForPair(
475 const MemOperand& operandA,
476 const MemOperand& operandB,
477 int access_size_log2) {
478 DCHECK(access_size_log2 >= 0);
479 DCHECK(access_size_log2 <= 3);
480 // Step one: check that they share the same base, that the mode is Offset
481 // and that the offset is a multiple of access size.
482 if (!operandA.base().Is(operandB.base()) ||
483 (operandA.addrmode() != Offset) ||
484 (operandB.addrmode() != Offset) ||
485 ((operandA.offset() & ((1 << access_size_log2) - 1)) != 0)) {
486 return kNotPair;
487 }
488 // Step two: check that the offsets are contiguous and that the range
489 // is OK for ldp/stp.
490 if ((operandB.offset() == operandA.offset() + (1 << access_size_log2)) &&
491 is_int7(operandA.offset() >> access_size_log2)) {
492 return kPairAB;
493 }
494 if ((operandA.offset() == operandB.offset() + (1 << access_size_log2)) &&
495 is_int7(operandB.offset() >> access_size_log2)) {
496 return kPairBA;
497 }
498 return kNotPair;
499 }
500
501
EmitGuard()502 void ConstPool::EmitGuard() {
503 #ifdef DEBUG
504 Instruction* instr = reinterpret_cast<Instruction*>(assm_->pc());
505 DCHECK(instr->preceding()->IsLdrLiteralX() &&
506 instr->preceding()->Rt() == xzr.code());
507 #endif
508 assm_->EmitPoolGuard();
509 }
510
511
EmitEntries()512 void ConstPool::EmitEntries() {
513 DCHECK(IsAligned(assm_->pc_offset(), 8));
514
515 typedef std::multimap<uint64_t, int>::const_iterator SharedEntriesIterator;
516 SharedEntriesIterator value_it;
517 // Iterate through the keys (constant pool values).
518 for (value_it = shared_entries_.begin();
519 value_it != shared_entries_.end();
520 value_it = shared_entries_.upper_bound(value_it->first)) {
521 std::pair<SharedEntriesIterator, SharedEntriesIterator> range;
522 uint64_t data = value_it->first;
523 range = shared_entries_.equal_range(data);
524 SharedEntriesIterator offset_it;
525 // Iterate through the offsets of a given key.
526 for (offset_it = range.first; offset_it != range.second; offset_it++) {
527 Instruction* instr = assm_->InstructionAt(offset_it->second);
528
529 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
530 DCHECK(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
531 instr->SetImmPCOffsetTarget(assm_->isolate(), assm_->pc());
532 }
533 assm_->dc64(data);
534 }
535 shared_entries_.clear();
536 shared_entries_count = 0;
537
538 // Emit unique entries.
539 std::vector<std::pair<uint64_t, int> >::const_iterator unique_it;
540 for (unique_it = unique_entries_.begin();
541 unique_it != unique_entries_.end();
542 unique_it++) {
543 Instruction* instr = assm_->InstructionAt(unique_it->second);
544
545 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
546 DCHECK(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
547 instr->SetImmPCOffsetTarget(assm_->isolate(), assm_->pc());
548 assm_->dc64(unique_it->first);
549 }
550 unique_entries_.clear();
551 first_use_ = -1;
552 }
553
554
555 // Assembler
Assembler(Isolate * isolate,void * buffer,int buffer_size)556 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
557 : AssemblerBase(isolate, buffer, buffer_size),
558 constpool_(this),
559 recorded_ast_id_(TypeFeedbackId::None()),
560 unresolved_branches_() {
561 const_pool_blocked_nesting_ = 0;
562 veneer_pool_blocked_nesting_ = 0;
563 Reset();
564 }
565
566
~Assembler()567 Assembler::~Assembler() {
568 DCHECK(constpool_.IsEmpty());
569 DCHECK(const_pool_blocked_nesting_ == 0);
570 DCHECK(veneer_pool_blocked_nesting_ == 0);
571 }
572
573
Reset()574 void Assembler::Reset() {
575 #ifdef DEBUG
576 DCHECK((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_));
577 DCHECK(const_pool_blocked_nesting_ == 0);
578 DCHECK(veneer_pool_blocked_nesting_ == 0);
579 DCHECK(unresolved_branches_.empty());
580 memset(buffer_, 0, pc_ - buffer_);
581 #endif
582 pc_ = buffer_;
583 reloc_info_writer.Reposition(reinterpret_cast<byte*>(buffer_ + buffer_size_),
584 reinterpret_cast<byte*>(pc_));
585 constpool_.Clear();
586 next_constant_pool_check_ = 0;
587 next_veneer_pool_check_ = kMaxInt;
588 no_const_pool_before_ = 0;
589 ClearRecordedAstId();
590 }
591
592
GetCode(CodeDesc * desc)593 void Assembler::GetCode(CodeDesc* desc) {
594 // Emit constant pool if necessary.
595 CheckConstPool(true, false);
596 DCHECK(constpool_.IsEmpty());
597
598 // Set up code descriptor.
599 if (desc) {
600 desc->buffer = reinterpret_cast<byte*>(buffer_);
601 desc->buffer_size = buffer_size_;
602 desc->instr_size = pc_offset();
603 desc->reloc_size =
604 static_cast<int>((reinterpret_cast<byte*>(buffer_) + buffer_size_) -
605 reloc_info_writer.pos());
606 desc->origin = this;
607 desc->constant_pool_size = 0;
608 desc->unwinding_info_size = 0;
609 desc->unwinding_info = nullptr;
610 }
611 }
612
613
Align(int m)614 void Assembler::Align(int m) {
615 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
616 while ((pc_offset() & (m - 1)) != 0) {
617 nop();
618 }
619 }
620
621
CheckLabelLinkChain(Label const * label)622 void Assembler::CheckLabelLinkChain(Label const * label) {
623 #ifdef DEBUG
624 if (label->is_linked()) {
625 static const int kMaxLinksToCheck = 64; // Avoid O(n2) behaviour.
626 int links_checked = 0;
627 int64_t linkoffset = label->pos();
628 bool end_of_chain = false;
629 while (!end_of_chain) {
630 if (++links_checked > kMaxLinksToCheck) break;
631 Instruction * link = InstructionAt(linkoffset);
632 int64_t linkpcoffset = link->ImmPCOffset();
633 int64_t prevlinkoffset = linkoffset + linkpcoffset;
634
635 end_of_chain = (linkoffset == prevlinkoffset);
636 linkoffset = linkoffset + linkpcoffset;
637 }
638 }
639 #endif
640 }
641
642
RemoveBranchFromLabelLinkChain(Instruction * branch,Label * label,Instruction * label_veneer)643 void Assembler::RemoveBranchFromLabelLinkChain(Instruction* branch,
644 Label* label,
645 Instruction* label_veneer) {
646 DCHECK(label->is_linked());
647
648 CheckLabelLinkChain(label);
649
650 Instruction* link = InstructionAt(label->pos());
651 Instruction* prev_link = link;
652 Instruction* next_link;
653 bool end_of_chain = false;
654
655 while (link != branch && !end_of_chain) {
656 next_link = link->ImmPCOffsetTarget();
657 end_of_chain = (link == next_link);
658 prev_link = link;
659 link = next_link;
660 }
661
662 DCHECK(branch == link);
663 next_link = branch->ImmPCOffsetTarget();
664
665 if (branch == prev_link) {
666 // The branch is the first instruction in the chain.
667 if (branch == next_link) {
668 // It is also the last instruction in the chain, so it is the only branch
669 // currently referring to this label.
670 label->Unuse();
671 } else {
672 label->link_to(
673 static_cast<int>(reinterpret_cast<byte*>(next_link) - buffer_));
674 }
675
676 } else if (branch == next_link) {
677 // The branch is the last (but not also the first) instruction in the chain.
678 prev_link->SetImmPCOffsetTarget(isolate(), prev_link);
679
680 } else {
681 // The branch is in the middle of the chain.
682 if (prev_link->IsTargetInImmPCOffsetRange(next_link)) {
683 prev_link->SetImmPCOffsetTarget(isolate(), next_link);
684 } else if (label_veneer != NULL) {
685 // Use the veneer for all previous links in the chain.
686 prev_link->SetImmPCOffsetTarget(isolate(), prev_link);
687
688 end_of_chain = false;
689 link = next_link;
690 while (!end_of_chain) {
691 next_link = link->ImmPCOffsetTarget();
692 end_of_chain = (link == next_link);
693 link->SetImmPCOffsetTarget(isolate(), label_veneer);
694 link = next_link;
695 }
696 } else {
697 // The assert below will fire.
698 // Some other work could be attempted to fix up the chain, but it would be
699 // rather complicated. If we crash here, we may want to consider using an
700 // other mechanism than a chain of branches.
701 //
702 // Note that this situation currently should not happen, as we always call
703 // this function with a veneer to the target label.
704 // However this could happen with a MacroAssembler in the following state:
705 // [previous code]
706 // B(label);
707 // [20KB code]
708 // Tbz(label); // First tbz. Pointing to unconditional branch.
709 // [20KB code]
710 // Tbz(label); // Second tbz. Pointing to the first tbz.
711 // [more code]
712 // and this function is called to remove the first tbz from the label link
713 // chain. Since tbz has a range of +-32KB, the second tbz cannot point to
714 // the unconditional branch.
715 CHECK(prev_link->IsTargetInImmPCOffsetRange(next_link));
716 UNREACHABLE();
717 }
718 }
719
720 CheckLabelLinkChain(label);
721 }
722
723
bind(Label * label)724 void Assembler::bind(Label* label) {
725 // Bind label to the address at pc_. All instructions (most likely branches)
726 // that are linked to this label will be updated to point to the newly-bound
727 // label.
728
729 DCHECK(!label->is_near_linked());
730 DCHECK(!label->is_bound());
731
732 DeleteUnresolvedBranchInfoForLabel(label);
733
734 // If the label is linked, the link chain looks something like this:
735 //
736 // |--I----I-------I-------L
737 // |---------------------->| pc_offset
738 // |-------------->| linkoffset = label->pos()
739 // |<------| link->ImmPCOffset()
740 // |------>| prevlinkoffset = linkoffset + link->ImmPCOffset()
741 //
742 // On each iteration, the last link is updated and then removed from the
743 // chain until only one remains. At that point, the label is bound.
744 //
745 // If the label is not linked, no preparation is required before binding.
746 while (label->is_linked()) {
747 int linkoffset = label->pos();
748 Instruction* link = InstructionAt(linkoffset);
749 int prevlinkoffset = linkoffset + static_cast<int>(link->ImmPCOffset());
750
751 CheckLabelLinkChain(label);
752
753 DCHECK(linkoffset >= 0);
754 DCHECK(linkoffset < pc_offset());
755 DCHECK((linkoffset > prevlinkoffset) ||
756 (linkoffset - prevlinkoffset == kStartOfLabelLinkChain));
757 DCHECK(prevlinkoffset >= 0);
758
759 // Update the link to point to the label.
760 if (link->IsUnresolvedInternalReference()) {
761 // Internal references do not get patched to an instruction but directly
762 // to an address.
763 internal_reference_positions_.push_back(linkoffset);
764 PatchingAssembler patcher(isolate(), link, 2);
765 patcher.dc64(reinterpret_cast<uintptr_t>(pc_));
766 } else {
767 link->SetImmPCOffsetTarget(isolate(),
768 reinterpret_cast<Instruction*>(pc_));
769 }
770
771 // Link the label to the previous link in the chain.
772 if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) {
773 // We hit kStartOfLabelLinkChain, so the chain is fully processed.
774 label->Unuse();
775 } else {
776 // Update the label for the next iteration.
777 label->link_to(prevlinkoffset);
778 }
779 }
780 label->bind_to(pc_offset());
781
782 DCHECK(label->is_bound());
783 DCHECK(!label->is_linked());
784 }
785
786
LinkAndGetByteOffsetTo(Label * label)787 int Assembler::LinkAndGetByteOffsetTo(Label* label) {
788 DCHECK(sizeof(*pc_) == 1);
789 CheckLabelLinkChain(label);
790
791 int offset;
792 if (label->is_bound()) {
793 // The label is bound, so it does not need to be updated. Referring
794 // instructions must link directly to the label as they will not be
795 // updated.
796 //
797 // In this case, label->pos() returns the offset of the label from the
798 // start of the buffer.
799 //
800 // Note that offset can be zero for self-referential instructions. (This
801 // could be useful for ADR, for example.)
802 offset = label->pos() - pc_offset();
803 DCHECK(offset <= 0);
804 } else {
805 if (label->is_linked()) {
806 // The label is linked, so the referring instruction should be added onto
807 // the end of the label's link chain.
808 //
809 // In this case, label->pos() returns the offset of the last linked
810 // instruction from the start of the buffer.
811 offset = label->pos() - pc_offset();
812 DCHECK(offset != kStartOfLabelLinkChain);
813 // Note that the offset here needs to be PC-relative only so that the
814 // first instruction in a buffer can link to an unbound label. Otherwise,
815 // the offset would be 0 for this case, and 0 is reserved for
816 // kStartOfLabelLinkChain.
817 } else {
818 // The label is unused, so it now becomes linked and the referring
819 // instruction is at the start of the new link chain.
820 offset = kStartOfLabelLinkChain;
821 }
822 // The instruction at pc is now the last link in the label's chain.
823 label->link_to(pc_offset());
824 }
825
826 return offset;
827 }
828
829
DeleteUnresolvedBranchInfoForLabelTraverse(Label * label)830 void Assembler::DeleteUnresolvedBranchInfoForLabelTraverse(Label* label) {
831 DCHECK(label->is_linked());
832 CheckLabelLinkChain(label);
833
834 int link_offset = label->pos();
835 int link_pcoffset;
836 bool end_of_chain = false;
837
838 while (!end_of_chain) {
839 Instruction * link = InstructionAt(link_offset);
840 link_pcoffset = static_cast<int>(link->ImmPCOffset());
841
842 // ADR instructions are not handled by veneers.
843 if (link->IsImmBranch()) {
844 int max_reachable_pc =
845 static_cast<int>(InstructionOffset(link) +
846 Instruction::ImmBranchRange(link->BranchType()));
847 typedef std::multimap<int, FarBranchInfo>::iterator unresolved_info_it;
848 std::pair<unresolved_info_it, unresolved_info_it> range;
849 range = unresolved_branches_.equal_range(max_reachable_pc);
850 unresolved_info_it it;
851 for (it = range.first; it != range.second; ++it) {
852 if (it->second.pc_offset_ == link_offset) {
853 unresolved_branches_.erase(it);
854 break;
855 }
856 }
857 }
858
859 end_of_chain = (link_pcoffset == 0);
860 link_offset = link_offset + link_pcoffset;
861 }
862 }
863
864
DeleteUnresolvedBranchInfoForLabel(Label * label)865 void Assembler::DeleteUnresolvedBranchInfoForLabel(Label* label) {
866 if (unresolved_branches_.empty()) {
867 DCHECK(next_veneer_pool_check_ == kMaxInt);
868 return;
869 }
870
871 if (label->is_linked()) {
872 // Branches to this label will be resolved when the label is bound, normally
873 // just after all the associated info has been deleted.
874 DeleteUnresolvedBranchInfoForLabelTraverse(label);
875 }
876 if (unresolved_branches_.empty()) {
877 next_veneer_pool_check_ = kMaxInt;
878 } else {
879 next_veneer_pool_check_ =
880 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
881 }
882 }
883
884
StartBlockConstPool()885 void Assembler::StartBlockConstPool() {
886 if (const_pool_blocked_nesting_++ == 0) {
887 // Prevent constant pool checks happening by setting the next check to
888 // the biggest possible offset.
889 next_constant_pool_check_ = kMaxInt;
890 }
891 }
892
893
EndBlockConstPool()894 void Assembler::EndBlockConstPool() {
895 if (--const_pool_blocked_nesting_ == 0) {
896 // Check the constant pool hasn't been blocked for too long.
897 DCHECK(pc_offset() < constpool_.MaxPcOffset());
898 // Two cases:
899 // * no_const_pool_before_ >= next_constant_pool_check_ and the emission is
900 // still blocked
901 // * no_const_pool_before_ < next_constant_pool_check_ and the next emit
902 // will trigger a check.
903 next_constant_pool_check_ = no_const_pool_before_;
904 }
905 }
906
907
is_const_pool_blocked() const908 bool Assembler::is_const_pool_blocked() const {
909 return (const_pool_blocked_nesting_ > 0) ||
910 (pc_offset() < no_const_pool_before_);
911 }
912
913
IsConstantPoolAt(Instruction * instr)914 bool Assembler::IsConstantPoolAt(Instruction* instr) {
915 // The constant pool marker is made of two instructions. These instructions
916 // will never be emitted by the JIT, so checking for the first one is enough:
917 // 0: ldr xzr, #<size of pool>
918 bool result = instr->IsLdrLiteralX() && (instr->Rt() == kZeroRegCode);
919
920 // It is still worth asserting the marker is complete.
921 // 4: blr xzr
922 DCHECK(!result || (instr->following()->IsBranchAndLinkToRegister() &&
923 instr->following()->Rn() == kZeroRegCode));
924
925 return result;
926 }
927
928
ConstantPoolSizeAt(Instruction * instr)929 int Assembler::ConstantPoolSizeAt(Instruction* instr) {
930 #ifdef USE_SIMULATOR
931 // Assembler::debug() embeds constants directly into the instruction stream.
932 // Although this is not a genuine constant pool, treat it like one to avoid
933 // disassembling the constants.
934 if ((instr->Mask(ExceptionMask) == HLT) &&
935 (instr->ImmException() == kImmExceptionIsDebug)) {
936 const char* message =
937 reinterpret_cast<const char*>(
938 instr->InstructionAtOffset(kDebugMessageOffset));
939 int size = static_cast<int>(kDebugMessageOffset + strlen(message) + 1);
940 return RoundUp(size, kInstructionSize) / kInstructionSize;
941 }
942 // Same for printf support, see MacroAssembler::CallPrintf().
943 if ((instr->Mask(ExceptionMask) == HLT) &&
944 (instr->ImmException() == kImmExceptionIsPrintf)) {
945 return kPrintfLength / kInstructionSize;
946 }
947 #endif
948 if (IsConstantPoolAt(instr)) {
949 return instr->ImmLLiteral();
950 } else {
951 return -1;
952 }
953 }
954
955
EmitPoolGuard()956 void Assembler::EmitPoolGuard() {
957 // We must generate only one instruction as this is used in scopes that
958 // control the size of the code generated.
959 Emit(BLR | Rn(xzr));
960 }
961
962
StartBlockVeneerPool()963 void Assembler::StartBlockVeneerPool() {
964 ++veneer_pool_blocked_nesting_;
965 }
966
967
EndBlockVeneerPool()968 void Assembler::EndBlockVeneerPool() {
969 if (--veneer_pool_blocked_nesting_ == 0) {
970 // Check the veneer pool hasn't been blocked for too long.
971 DCHECK(unresolved_branches_.empty() ||
972 (pc_offset() < unresolved_branches_first_limit()));
973 }
974 }
975
976
br(const Register & xn)977 void Assembler::br(const Register& xn) {
978 DCHECK(xn.Is64Bits());
979 Emit(BR | Rn(xn));
980 }
981
982
blr(const Register & xn)983 void Assembler::blr(const Register& xn) {
984 DCHECK(xn.Is64Bits());
985 // The pattern 'blr xzr' is used as a guard to detect when execution falls
986 // through the constant pool. It should not be emitted.
987 DCHECK(!xn.Is(xzr));
988 Emit(BLR | Rn(xn));
989 }
990
991
ret(const Register & xn)992 void Assembler::ret(const Register& xn) {
993 DCHECK(xn.Is64Bits());
994 Emit(RET | Rn(xn));
995 }
996
997
b(int imm26)998 void Assembler::b(int imm26) {
999 Emit(B | ImmUncondBranch(imm26));
1000 }
1001
1002
b(Label * label)1003 void Assembler::b(Label* label) {
1004 b(LinkAndGetInstructionOffsetTo(label));
1005 }
1006
1007
b(int imm19,Condition cond)1008 void Assembler::b(int imm19, Condition cond) {
1009 Emit(B_cond | ImmCondBranch(imm19) | cond);
1010 }
1011
1012
b(Label * label,Condition cond)1013 void Assembler::b(Label* label, Condition cond) {
1014 b(LinkAndGetInstructionOffsetTo(label), cond);
1015 }
1016
1017
bl(int imm26)1018 void Assembler::bl(int imm26) {
1019 Emit(BL | ImmUncondBranch(imm26));
1020 }
1021
1022
bl(Label * label)1023 void Assembler::bl(Label* label) {
1024 bl(LinkAndGetInstructionOffsetTo(label));
1025 }
1026
1027
cbz(const Register & rt,int imm19)1028 void Assembler::cbz(const Register& rt,
1029 int imm19) {
1030 Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));
1031 }
1032
1033
cbz(const Register & rt,Label * label)1034 void Assembler::cbz(const Register& rt,
1035 Label* label) {
1036 cbz(rt, LinkAndGetInstructionOffsetTo(label));
1037 }
1038
1039
cbnz(const Register & rt,int imm19)1040 void Assembler::cbnz(const Register& rt,
1041 int imm19) {
1042 Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));
1043 }
1044
1045
cbnz(const Register & rt,Label * label)1046 void Assembler::cbnz(const Register& rt,
1047 Label* label) {
1048 cbnz(rt, LinkAndGetInstructionOffsetTo(label));
1049 }
1050
1051
tbz(const Register & rt,unsigned bit_pos,int imm14)1052 void Assembler::tbz(const Register& rt,
1053 unsigned bit_pos,
1054 int imm14) {
1055 DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
1056 Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
1057 }
1058
1059
tbz(const Register & rt,unsigned bit_pos,Label * label)1060 void Assembler::tbz(const Register& rt,
1061 unsigned bit_pos,
1062 Label* label) {
1063 tbz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
1064 }
1065
1066
tbnz(const Register & rt,unsigned bit_pos,int imm14)1067 void Assembler::tbnz(const Register& rt,
1068 unsigned bit_pos,
1069 int imm14) {
1070 DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
1071 Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
1072 }
1073
1074
tbnz(const Register & rt,unsigned bit_pos,Label * label)1075 void Assembler::tbnz(const Register& rt,
1076 unsigned bit_pos,
1077 Label* label) {
1078 tbnz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
1079 }
1080
1081
adr(const Register & rd,int imm21)1082 void Assembler::adr(const Register& rd, int imm21) {
1083 DCHECK(rd.Is64Bits());
1084 Emit(ADR | ImmPCRelAddress(imm21) | Rd(rd));
1085 }
1086
1087
adr(const Register & rd,Label * label)1088 void Assembler::adr(const Register& rd, Label* label) {
1089 adr(rd, LinkAndGetByteOffsetTo(label));
1090 }
1091
1092
add(const Register & rd,const Register & rn,const Operand & operand)1093 void Assembler::add(const Register& rd,
1094 const Register& rn,
1095 const Operand& operand) {
1096 AddSub(rd, rn, operand, LeaveFlags, ADD);
1097 }
1098
1099
adds(const Register & rd,const Register & rn,const Operand & operand)1100 void Assembler::adds(const Register& rd,
1101 const Register& rn,
1102 const Operand& operand) {
1103 AddSub(rd, rn, operand, SetFlags, ADD);
1104 }
1105
1106
cmn(const Register & rn,const Operand & operand)1107 void Assembler::cmn(const Register& rn,
1108 const Operand& operand) {
1109 Register zr = AppropriateZeroRegFor(rn);
1110 adds(zr, rn, operand);
1111 }
1112
1113
sub(const Register & rd,const Register & rn,const Operand & operand)1114 void Assembler::sub(const Register& rd,
1115 const Register& rn,
1116 const Operand& operand) {
1117 AddSub(rd, rn, operand, LeaveFlags, SUB);
1118 }
1119
1120
subs(const Register & rd,const Register & rn,const Operand & operand)1121 void Assembler::subs(const Register& rd,
1122 const Register& rn,
1123 const Operand& operand) {
1124 AddSub(rd, rn, operand, SetFlags, SUB);
1125 }
1126
1127
cmp(const Register & rn,const Operand & operand)1128 void Assembler::cmp(const Register& rn, const Operand& operand) {
1129 Register zr = AppropriateZeroRegFor(rn);
1130 subs(zr, rn, operand);
1131 }
1132
1133
neg(const Register & rd,const Operand & operand)1134 void Assembler::neg(const Register& rd, const Operand& operand) {
1135 Register zr = AppropriateZeroRegFor(rd);
1136 sub(rd, zr, operand);
1137 }
1138
1139
negs(const Register & rd,const Operand & operand)1140 void Assembler::negs(const Register& rd, const Operand& operand) {
1141 Register zr = AppropriateZeroRegFor(rd);
1142 subs(rd, zr, operand);
1143 }
1144
1145
adc(const Register & rd,const Register & rn,const Operand & operand)1146 void Assembler::adc(const Register& rd,
1147 const Register& rn,
1148 const Operand& operand) {
1149 AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);
1150 }
1151
1152
adcs(const Register & rd,const Register & rn,const Operand & operand)1153 void Assembler::adcs(const Register& rd,
1154 const Register& rn,
1155 const Operand& operand) {
1156 AddSubWithCarry(rd, rn, operand, SetFlags, ADC);
1157 }
1158
1159
sbc(const Register & rd,const Register & rn,const Operand & operand)1160 void Assembler::sbc(const Register& rd,
1161 const Register& rn,
1162 const Operand& operand) {
1163 AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);
1164 }
1165
1166
sbcs(const Register & rd,const Register & rn,const Operand & operand)1167 void Assembler::sbcs(const Register& rd,
1168 const Register& rn,
1169 const Operand& operand) {
1170 AddSubWithCarry(rd, rn, operand, SetFlags, SBC);
1171 }
1172
1173
ngc(const Register & rd,const Operand & operand)1174 void Assembler::ngc(const Register& rd, const Operand& operand) {
1175 Register zr = AppropriateZeroRegFor(rd);
1176 sbc(rd, zr, operand);
1177 }
1178
1179
ngcs(const Register & rd,const Operand & operand)1180 void Assembler::ngcs(const Register& rd, const Operand& operand) {
1181 Register zr = AppropriateZeroRegFor(rd);
1182 sbcs(rd, zr, operand);
1183 }
1184
1185
1186 // Logical instructions.
and_(const Register & rd,const Register & rn,const Operand & operand)1187 void Assembler::and_(const Register& rd,
1188 const Register& rn,
1189 const Operand& operand) {
1190 Logical(rd, rn, operand, AND);
1191 }
1192
1193
ands(const Register & rd,const Register & rn,const Operand & operand)1194 void Assembler::ands(const Register& rd,
1195 const Register& rn,
1196 const Operand& operand) {
1197 Logical(rd, rn, operand, ANDS);
1198 }
1199
1200
tst(const Register & rn,const Operand & operand)1201 void Assembler::tst(const Register& rn,
1202 const Operand& operand) {
1203 ands(AppropriateZeroRegFor(rn), rn, operand);
1204 }
1205
1206
bic(const Register & rd,const Register & rn,const Operand & operand)1207 void Assembler::bic(const Register& rd,
1208 const Register& rn,
1209 const Operand& operand) {
1210 Logical(rd, rn, operand, BIC);
1211 }
1212
1213
bics(const Register & rd,const Register & rn,const Operand & operand)1214 void Assembler::bics(const Register& rd,
1215 const Register& rn,
1216 const Operand& operand) {
1217 Logical(rd, rn, operand, BICS);
1218 }
1219
1220
orr(const Register & rd,const Register & rn,const Operand & operand)1221 void Assembler::orr(const Register& rd,
1222 const Register& rn,
1223 const Operand& operand) {
1224 Logical(rd, rn, operand, ORR);
1225 }
1226
1227
orn(const Register & rd,const Register & rn,const Operand & operand)1228 void Assembler::orn(const Register& rd,
1229 const Register& rn,
1230 const Operand& operand) {
1231 Logical(rd, rn, operand, ORN);
1232 }
1233
1234
eor(const Register & rd,const Register & rn,const Operand & operand)1235 void Assembler::eor(const Register& rd,
1236 const Register& rn,
1237 const Operand& operand) {
1238 Logical(rd, rn, operand, EOR);
1239 }
1240
1241
eon(const Register & rd,const Register & rn,const Operand & operand)1242 void Assembler::eon(const Register& rd,
1243 const Register& rn,
1244 const Operand& operand) {
1245 Logical(rd, rn, operand, EON);
1246 }
1247
1248
lslv(const Register & rd,const Register & rn,const Register & rm)1249 void Assembler::lslv(const Register& rd,
1250 const Register& rn,
1251 const Register& rm) {
1252 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1253 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1254 Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));
1255 }
1256
1257
lsrv(const Register & rd,const Register & rn,const Register & rm)1258 void Assembler::lsrv(const Register& rd,
1259 const Register& rn,
1260 const Register& rm) {
1261 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1262 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1263 Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));
1264 }
1265
1266
asrv(const Register & rd,const Register & rn,const Register & rm)1267 void Assembler::asrv(const Register& rd,
1268 const Register& rn,
1269 const Register& rm) {
1270 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1271 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1272 Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));
1273 }
1274
1275
rorv(const Register & rd,const Register & rn,const Register & rm)1276 void Assembler::rorv(const Register& rd,
1277 const Register& rn,
1278 const Register& rm) {
1279 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1280 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1281 Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));
1282 }
1283
1284
1285 // Bitfield operations.
bfm(const Register & rd,const Register & rn,int immr,int imms)1286 void Assembler::bfm(const Register& rd, const Register& rn, int immr,
1287 int imms) {
1288 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1289 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1290 Emit(SF(rd) | BFM | N |
1291 ImmR(immr, rd.SizeInBits()) |
1292 ImmS(imms, rn.SizeInBits()) |
1293 Rn(rn) | Rd(rd));
1294 }
1295
1296
sbfm(const Register & rd,const Register & rn,int immr,int imms)1297 void Assembler::sbfm(const Register& rd, const Register& rn, int immr,
1298 int imms) {
1299 DCHECK(rd.Is64Bits() || rn.Is32Bits());
1300 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1301 Emit(SF(rd) | SBFM | N |
1302 ImmR(immr, rd.SizeInBits()) |
1303 ImmS(imms, rn.SizeInBits()) |
1304 Rn(rn) | Rd(rd));
1305 }
1306
1307
ubfm(const Register & rd,const Register & rn,int immr,int imms)1308 void Assembler::ubfm(const Register& rd, const Register& rn, int immr,
1309 int imms) {
1310 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1311 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1312 Emit(SF(rd) | UBFM | N |
1313 ImmR(immr, rd.SizeInBits()) |
1314 ImmS(imms, rn.SizeInBits()) |
1315 Rn(rn) | Rd(rd));
1316 }
1317
1318
extr(const Register & rd,const Register & rn,const Register & rm,int lsb)1319 void Assembler::extr(const Register& rd, const Register& rn, const Register& rm,
1320 int lsb) {
1321 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1322 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1323 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
1324 Emit(SF(rd) | EXTR | N | Rm(rm) |
1325 ImmS(lsb, rn.SizeInBits()) | Rn(rn) | Rd(rd));
1326 }
1327
1328
csel(const Register & rd,const Register & rn,const Register & rm,Condition cond)1329 void Assembler::csel(const Register& rd,
1330 const Register& rn,
1331 const Register& rm,
1332 Condition cond) {
1333 ConditionalSelect(rd, rn, rm, cond, CSEL);
1334 }
1335
1336
csinc(const Register & rd,const Register & rn,const Register & rm,Condition cond)1337 void Assembler::csinc(const Register& rd,
1338 const Register& rn,
1339 const Register& rm,
1340 Condition cond) {
1341 ConditionalSelect(rd, rn, rm, cond, CSINC);
1342 }
1343
1344
csinv(const Register & rd,const Register & rn,const Register & rm,Condition cond)1345 void Assembler::csinv(const Register& rd,
1346 const Register& rn,
1347 const Register& rm,
1348 Condition cond) {
1349 ConditionalSelect(rd, rn, rm, cond, CSINV);
1350 }
1351
1352
csneg(const Register & rd,const Register & rn,const Register & rm,Condition cond)1353 void Assembler::csneg(const Register& rd,
1354 const Register& rn,
1355 const Register& rm,
1356 Condition cond) {
1357 ConditionalSelect(rd, rn, rm, cond, CSNEG);
1358 }
1359
1360
cset(const Register & rd,Condition cond)1361 void Assembler::cset(const Register &rd, Condition cond) {
1362 DCHECK((cond != al) && (cond != nv));
1363 Register zr = AppropriateZeroRegFor(rd);
1364 csinc(rd, zr, zr, NegateCondition(cond));
1365 }
1366
1367
csetm(const Register & rd,Condition cond)1368 void Assembler::csetm(const Register &rd, Condition cond) {
1369 DCHECK((cond != al) && (cond != nv));
1370 Register zr = AppropriateZeroRegFor(rd);
1371 csinv(rd, zr, zr, NegateCondition(cond));
1372 }
1373
1374
cinc(const Register & rd,const Register & rn,Condition cond)1375 void Assembler::cinc(const Register &rd, const Register &rn, Condition cond) {
1376 DCHECK((cond != al) && (cond != nv));
1377 csinc(rd, rn, rn, NegateCondition(cond));
1378 }
1379
1380
cinv(const Register & rd,const Register & rn,Condition cond)1381 void Assembler::cinv(const Register &rd, const Register &rn, Condition cond) {
1382 DCHECK((cond != al) && (cond != nv));
1383 csinv(rd, rn, rn, NegateCondition(cond));
1384 }
1385
1386
cneg(const Register & rd,const Register & rn,Condition cond)1387 void Assembler::cneg(const Register &rd, const Register &rn, Condition cond) {
1388 DCHECK((cond != al) && (cond != nv));
1389 csneg(rd, rn, rn, NegateCondition(cond));
1390 }
1391
1392
ConditionalSelect(const Register & rd,const Register & rn,const Register & rm,Condition cond,ConditionalSelectOp op)1393 void Assembler::ConditionalSelect(const Register& rd,
1394 const Register& rn,
1395 const Register& rm,
1396 Condition cond,
1397 ConditionalSelectOp op) {
1398 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1399 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1400 Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));
1401 }
1402
1403
ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1404 void Assembler::ccmn(const Register& rn,
1405 const Operand& operand,
1406 StatusFlags nzcv,
1407 Condition cond) {
1408 ConditionalCompare(rn, operand, nzcv, cond, CCMN);
1409 }
1410
1411
ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1412 void Assembler::ccmp(const Register& rn,
1413 const Operand& operand,
1414 StatusFlags nzcv,
1415 Condition cond) {
1416 ConditionalCompare(rn, operand, nzcv, cond, CCMP);
1417 }
1418
1419
DataProcessing3Source(const Register & rd,const Register & rn,const Register & rm,const Register & ra,DataProcessing3SourceOp op)1420 void Assembler::DataProcessing3Source(const Register& rd,
1421 const Register& rn,
1422 const Register& rm,
1423 const Register& ra,
1424 DataProcessing3SourceOp op) {
1425 Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));
1426 }
1427
1428
mul(const Register & rd,const Register & rn,const Register & rm)1429 void Assembler::mul(const Register& rd,
1430 const Register& rn,
1431 const Register& rm) {
1432 DCHECK(AreSameSizeAndType(rd, rn, rm));
1433 Register zr = AppropriateZeroRegFor(rn);
1434 DataProcessing3Source(rd, rn, rm, zr, MADD);
1435 }
1436
1437
madd(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1438 void Assembler::madd(const Register& rd,
1439 const Register& rn,
1440 const Register& rm,
1441 const Register& ra) {
1442 DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
1443 DataProcessing3Source(rd, rn, rm, ra, MADD);
1444 }
1445
1446
mneg(const Register & rd,const Register & rn,const Register & rm)1447 void Assembler::mneg(const Register& rd,
1448 const Register& rn,
1449 const Register& rm) {
1450 DCHECK(AreSameSizeAndType(rd, rn, rm));
1451 Register zr = AppropriateZeroRegFor(rn);
1452 DataProcessing3Source(rd, rn, rm, zr, MSUB);
1453 }
1454
1455
msub(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1456 void Assembler::msub(const Register& rd,
1457 const Register& rn,
1458 const Register& rm,
1459 const Register& ra) {
1460 DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
1461 DataProcessing3Source(rd, rn, rm, ra, MSUB);
1462 }
1463
1464
smaddl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1465 void Assembler::smaddl(const Register& rd,
1466 const Register& rn,
1467 const Register& rm,
1468 const Register& ra) {
1469 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1470 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1471 DataProcessing3Source(rd, rn, rm, ra, SMADDL_x);
1472 }
1473
1474
smsubl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1475 void Assembler::smsubl(const Register& rd,
1476 const Register& rn,
1477 const Register& rm,
1478 const Register& ra) {
1479 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1480 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1481 DataProcessing3Source(rd, rn, rm, ra, SMSUBL_x);
1482 }
1483
1484
umaddl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1485 void Assembler::umaddl(const Register& rd,
1486 const Register& rn,
1487 const Register& rm,
1488 const Register& ra) {
1489 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1490 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1491 DataProcessing3Source(rd, rn, rm, ra, UMADDL_x);
1492 }
1493
1494
umsubl(const Register & rd,const Register & rn,const Register & rm,const Register & ra)1495 void Assembler::umsubl(const Register& rd,
1496 const Register& rn,
1497 const Register& rm,
1498 const Register& ra) {
1499 DCHECK(rd.Is64Bits() && ra.Is64Bits());
1500 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1501 DataProcessing3Source(rd, rn, rm, ra, UMSUBL_x);
1502 }
1503
1504
smull(const Register & rd,const Register & rn,const Register & rm)1505 void Assembler::smull(const Register& rd,
1506 const Register& rn,
1507 const Register& rm) {
1508 DCHECK(rd.Is64Bits());
1509 DCHECK(rn.Is32Bits() && rm.Is32Bits());
1510 DataProcessing3Source(rd, rn, rm, xzr, SMADDL_x);
1511 }
1512
1513
smulh(const Register & rd,const Register & rn,const Register & rm)1514 void Assembler::smulh(const Register& rd,
1515 const Register& rn,
1516 const Register& rm) {
1517 DCHECK(AreSameSizeAndType(rd, rn, rm));
1518 DataProcessing3Source(rd, rn, rm, xzr, SMULH_x);
1519 }
1520
1521
sdiv(const Register & rd,const Register & rn,const Register & rm)1522 void Assembler::sdiv(const Register& rd,
1523 const Register& rn,
1524 const Register& rm) {
1525 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1526 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1527 Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));
1528 }
1529
1530
udiv(const Register & rd,const Register & rn,const Register & rm)1531 void Assembler::udiv(const Register& rd,
1532 const Register& rn,
1533 const Register& rm) {
1534 DCHECK(rd.SizeInBits() == rn.SizeInBits());
1535 DCHECK(rd.SizeInBits() == rm.SizeInBits());
1536 Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));
1537 }
1538
1539
rbit(const Register & rd,const Register & rn)1540 void Assembler::rbit(const Register& rd,
1541 const Register& rn) {
1542 DataProcessing1Source(rd, rn, RBIT);
1543 }
1544
1545
rev16(const Register & rd,const Register & rn)1546 void Assembler::rev16(const Register& rd,
1547 const Register& rn) {
1548 DataProcessing1Source(rd, rn, REV16);
1549 }
1550
1551
rev32(const Register & rd,const Register & rn)1552 void Assembler::rev32(const Register& rd,
1553 const Register& rn) {
1554 DCHECK(rd.Is64Bits());
1555 DataProcessing1Source(rd, rn, REV);
1556 }
1557
1558
rev(const Register & rd,const Register & rn)1559 void Assembler::rev(const Register& rd,
1560 const Register& rn) {
1561 DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);
1562 }
1563
1564
clz(const Register & rd,const Register & rn)1565 void Assembler::clz(const Register& rd,
1566 const Register& rn) {
1567 DataProcessing1Source(rd, rn, CLZ);
1568 }
1569
1570
cls(const Register & rd,const Register & rn)1571 void Assembler::cls(const Register& rd,
1572 const Register& rn) {
1573 DataProcessing1Source(rd, rn, CLS);
1574 }
1575
1576
ldp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & src)1577 void Assembler::ldp(const CPURegister& rt,
1578 const CPURegister& rt2,
1579 const MemOperand& src) {
1580 LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
1581 }
1582
1583
stp(const CPURegister & rt,const CPURegister & rt2,const MemOperand & dst)1584 void Assembler::stp(const CPURegister& rt,
1585 const CPURegister& rt2,
1586 const MemOperand& dst) {
1587 LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
1588 }
1589
1590
ldpsw(const Register & rt,const Register & rt2,const MemOperand & src)1591 void Assembler::ldpsw(const Register& rt,
1592 const Register& rt2,
1593 const MemOperand& src) {
1594 DCHECK(rt.Is64Bits());
1595 LoadStorePair(rt, rt2, src, LDPSW_x);
1596 }
1597
1598
LoadStorePair(const CPURegister & rt,const CPURegister & rt2,const MemOperand & addr,LoadStorePairOp op)1599 void Assembler::LoadStorePair(const CPURegister& rt,
1600 const CPURegister& rt2,
1601 const MemOperand& addr,
1602 LoadStorePairOp op) {
1603 // 'rt' and 'rt2' can only be aliased for stores.
1604 DCHECK(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));
1605 DCHECK(AreSameSizeAndType(rt, rt2));
1606 DCHECK(IsImmLSPair(addr.offset(), CalcLSPairDataSize(op)));
1607 int offset = static_cast<int>(addr.offset());
1608
1609 Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
1610 ImmLSPair(offset, CalcLSPairDataSize(op));
1611
1612 Instr addrmodeop;
1613 if (addr.IsImmediateOffset()) {
1614 addrmodeop = LoadStorePairOffsetFixed;
1615 } else {
1616 // Pre-index and post-index modes.
1617 DCHECK(!rt.Is(addr.base()));
1618 DCHECK(!rt2.Is(addr.base()));
1619 DCHECK(addr.offset() != 0);
1620 if (addr.IsPreIndex()) {
1621 addrmodeop = LoadStorePairPreIndexFixed;
1622 } else {
1623 DCHECK(addr.IsPostIndex());
1624 addrmodeop = LoadStorePairPostIndexFixed;
1625 }
1626 }
1627 Emit(addrmodeop | memop);
1628 }
1629
1630
1631 // Memory instructions.
ldrb(const Register & rt,const MemOperand & src)1632 void Assembler::ldrb(const Register& rt, const MemOperand& src) {
1633 LoadStore(rt, src, LDRB_w);
1634 }
1635
1636
strb(const Register & rt,const MemOperand & dst)1637 void Assembler::strb(const Register& rt, const MemOperand& dst) {
1638 LoadStore(rt, dst, STRB_w);
1639 }
1640
1641
ldrsb(const Register & rt,const MemOperand & src)1642 void Assembler::ldrsb(const Register& rt, const MemOperand& src) {
1643 LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w);
1644 }
1645
1646
ldrh(const Register & rt,const MemOperand & src)1647 void Assembler::ldrh(const Register& rt, const MemOperand& src) {
1648 LoadStore(rt, src, LDRH_w);
1649 }
1650
1651
strh(const Register & rt,const MemOperand & dst)1652 void Assembler::strh(const Register& rt, const MemOperand& dst) {
1653 LoadStore(rt, dst, STRH_w);
1654 }
1655
1656
ldrsh(const Register & rt,const MemOperand & src)1657 void Assembler::ldrsh(const Register& rt, const MemOperand& src) {
1658 LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w);
1659 }
1660
1661
ldr(const CPURegister & rt,const MemOperand & src)1662 void Assembler::ldr(const CPURegister& rt, const MemOperand& src) {
1663 LoadStore(rt, src, LoadOpFor(rt));
1664 }
1665
1666
str(const CPURegister & rt,const MemOperand & src)1667 void Assembler::str(const CPURegister& rt, const MemOperand& src) {
1668 LoadStore(rt, src, StoreOpFor(rt));
1669 }
1670
1671
ldrsw(const Register & rt,const MemOperand & src)1672 void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
1673 DCHECK(rt.Is64Bits());
1674 LoadStore(rt, src, LDRSW_x);
1675 }
1676
1677
ldr_pcrel(const CPURegister & rt,int imm19)1678 void Assembler::ldr_pcrel(const CPURegister& rt, int imm19) {
1679 // The pattern 'ldr xzr, #offset' is used to indicate the beginning of a
1680 // constant pool. It should not be emitted.
1681 DCHECK(!rt.IsZero());
1682 Emit(LoadLiteralOpFor(rt) | ImmLLiteral(imm19) | Rt(rt));
1683 }
1684
1685
ldr(const CPURegister & rt,const Immediate & imm)1686 void Assembler::ldr(const CPURegister& rt, const Immediate& imm) {
1687 // Currently we only support 64-bit literals.
1688 DCHECK(rt.Is64Bits());
1689
1690 RecordRelocInfo(imm.rmode(), imm.value());
1691 BlockConstPoolFor(1);
1692 // The load will be patched when the constpool is emitted, patching code
1693 // expect a load literal with offset 0.
1694 ldr_pcrel(rt, 0);
1695 }
1696
ldar(const Register & rt,const Register & rn)1697 void Assembler::ldar(const Register& rt, const Register& rn) {
1698 DCHECK(rn.Is64Bits());
1699 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? LDAR_w : LDAR_x;
1700 Emit(op | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1701 }
1702
ldaxr(const Register & rt,const Register & rn)1703 void Assembler::ldaxr(const Register& rt, const Register& rn) {
1704 DCHECK(rn.Is64Bits());
1705 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? LDAXR_w : LDAXR_x;
1706 Emit(op | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1707 }
1708
stlr(const Register & rt,const Register & rn)1709 void Assembler::stlr(const Register& rt, const Register& rn) {
1710 DCHECK(rn.Is64Bits());
1711 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? STLR_w : STLR_x;
1712 Emit(op | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1713 }
1714
stlxr(const Register & rs,const Register & rt,const Register & rn)1715 void Assembler::stlxr(const Register& rs, const Register& rt,
1716 const Register& rn) {
1717 DCHECK(rs.Is32Bits());
1718 DCHECK(rn.Is64Bits());
1719 LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? STLXR_w : STLXR_x;
1720 Emit(op | Rs(rs) | Rt2(x31) | Rn(rn) | Rt(rt));
1721 }
1722
ldarb(const Register & rt,const Register & rn)1723 void Assembler::ldarb(const Register& rt, const Register& rn) {
1724 DCHECK(rt.Is32Bits());
1725 DCHECK(rn.Is64Bits());
1726 Emit(LDAR_b | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1727 }
1728
ldaxrb(const Register & rt,const Register & rn)1729 void Assembler::ldaxrb(const Register& rt, const Register& rn) {
1730 DCHECK(rt.Is32Bits());
1731 DCHECK(rn.Is64Bits());
1732 Emit(LDAXR_b | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1733 }
1734
stlrb(const Register & rt,const Register & rn)1735 void Assembler::stlrb(const Register& rt, const Register& rn) {
1736 DCHECK(rt.Is32Bits());
1737 DCHECK(rn.Is64Bits());
1738 Emit(STLR_b | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1739 }
1740
stlxrb(const Register & rs,const Register & rt,const Register & rn)1741 void Assembler::stlxrb(const Register& rs, const Register& rt,
1742 const Register& rn) {
1743 DCHECK(rs.Is32Bits());
1744 DCHECK(rt.Is32Bits());
1745 DCHECK(rn.Is64Bits());
1746 Emit(STLXR_b | Rs(rs) | Rt2(x31) | Rn(rn) | Rt(rt));
1747 }
1748
ldarh(const Register & rt,const Register & rn)1749 void Assembler::ldarh(const Register& rt, const Register& rn) {
1750 DCHECK(rt.Is32Bits());
1751 DCHECK(rn.Is64Bits());
1752 Emit(LDAR_h | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1753 }
1754
ldaxrh(const Register & rt,const Register & rn)1755 void Assembler::ldaxrh(const Register& rt, const Register& rn) {
1756 DCHECK(rt.Is32Bits());
1757 DCHECK(rn.Is64Bits());
1758 Emit(LDAXR_h | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1759 }
1760
stlrh(const Register & rt,const Register & rn)1761 void Assembler::stlrh(const Register& rt, const Register& rn) {
1762 DCHECK(rt.Is32Bits());
1763 DCHECK(rn.Is64Bits());
1764 Emit(STLR_h | Rs(x31) | Rt2(x31) | Rn(rn) | Rt(rt));
1765 }
1766
stlxrh(const Register & rs,const Register & rt,const Register & rn)1767 void Assembler::stlxrh(const Register& rs, const Register& rt,
1768 const Register& rn) {
1769 DCHECK(rs.Is32Bits());
1770 DCHECK(rt.Is32Bits());
1771 DCHECK(rn.Is64Bits());
1772 Emit(STLXR_h | Rs(rs) | Rt2(x31) | Rn(rn) | Rt(rt));
1773 }
1774
mov(const Register & rd,const Register & rm)1775 void Assembler::mov(const Register& rd, const Register& rm) {
1776 // Moves involving the stack pointer are encoded as add immediate with
1777 // second operand of zero. Otherwise, orr with first operand zr is
1778 // used.
1779 if (rd.IsSP() || rm.IsSP()) {
1780 add(rd, rm, 0);
1781 } else {
1782 orr(rd, AppropriateZeroRegFor(rd), rm);
1783 }
1784 }
1785
1786
mvn(const Register & rd,const Operand & operand)1787 void Assembler::mvn(const Register& rd, const Operand& operand) {
1788 orn(rd, AppropriateZeroRegFor(rd), operand);
1789 }
1790
1791
mrs(const Register & rt,SystemRegister sysreg)1792 void Assembler::mrs(const Register& rt, SystemRegister sysreg) {
1793 DCHECK(rt.Is64Bits());
1794 Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt));
1795 }
1796
1797
msr(SystemRegister sysreg,const Register & rt)1798 void Assembler::msr(SystemRegister sysreg, const Register& rt) {
1799 DCHECK(rt.Is64Bits());
1800 Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg));
1801 }
1802
1803
hint(SystemHint code)1804 void Assembler::hint(SystemHint code) {
1805 Emit(HINT | ImmHint(code) | Rt(xzr));
1806 }
1807
1808
dmb(BarrierDomain domain,BarrierType type)1809 void Assembler::dmb(BarrierDomain domain, BarrierType type) {
1810 Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));
1811 }
1812
1813
dsb(BarrierDomain domain,BarrierType type)1814 void Assembler::dsb(BarrierDomain domain, BarrierType type) {
1815 Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));
1816 }
1817
1818
isb()1819 void Assembler::isb() {
1820 Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));
1821 }
1822
1823
fmov(FPRegister fd,double imm)1824 void Assembler::fmov(FPRegister fd, double imm) {
1825 DCHECK(fd.Is64Bits());
1826 DCHECK(IsImmFP64(imm));
1827 Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm));
1828 }
1829
1830
fmov(FPRegister fd,float imm)1831 void Assembler::fmov(FPRegister fd, float imm) {
1832 DCHECK(fd.Is32Bits());
1833 DCHECK(IsImmFP32(imm));
1834 Emit(FMOV_s_imm | Rd(fd) | ImmFP32(imm));
1835 }
1836
1837
fmov(Register rd,FPRegister fn)1838 void Assembler::fmov(Register rd, FPRegister fn) {
1839 DCHECK(rd.SizeInBits() == fn.SizeInBits());
1840 FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd;
1841 Emit(op | Rd(rd) | Rn(fn));
1842 }
1843
1844
fmov(FPRegister fd,Register rn)1845 void Assembler::fmov(FPRegister fd, Register rn) {
1846 DCHECK(fd.SizeInBits() == rn.SizeInBits());
1847 FPIntegerConvertOp op = fd.Is32Bits() ? FMOV_sw : FMOV_dx;
1848 Emit(op | Rd(fd) | Rn(rn));
1849 }
1850
1851
fmov(FPRegister fd,FPRegister fn)1852 void Assembler::fmov(FPRegister fd, FPRegister fn) {
1853 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1854 Emit(FPType(fd) | FMOV | Rd(fd) | Rn(fn));
1855 }
1856
1857
fadd(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1858 void Assembler::fadd(const FPRegister& fd,
1859 const FPRegister& fn,
1860 const FPRegister& fm) {
1861 FPDataProcessing2Source(fd, fn, fm, FADD);
1862 }
1863
1864
fsub(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1865 void Assembler::fsub(const FPRegister& fd,
1866 const FPRegister& fn,
1867 const FPRegister& fm) {
1868 FPDataProcessing2Source(fd, fn, fm, FSUB);
1869 }
1870
1871
fmul(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1872 void Assembler::fmul(const FPRegister& fd,
1873 const FPRegister& fn,
1874 const FPRegister& fm) {
1875 FPDataProcessing2Source(fd, fn, fm, FMUL);
1876 }
1877
1878
fmadd(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,const FPRegister & fa)1879 void Assembler::fmadd(const FPRegister& fd,
1880 const FPRegister& fn,
1881 const FPRegister& fm,
1882 const FPRegister& fa) {
1883 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d);
1884 }
1885
1886
fmsub(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,const FPRegister & fa)1887 void Assembler::fmsub(const FPRegister& fd,
1888 const FPRegister& fn,
1889 const FPRegister& fm,
1890 const FPRegister& fa) {
1891 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d);
1892 }
1893
1894
fnmadd(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,const FPRegister & fa)1895 void Assembler::fnmadd(const FPRegister& fd,
1896 const FPRegister& fn,
1897 const FPRegister& fm,
1898 const FPRegister& fa) {
1899 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d);
1900 }
1901
1902
fnmsub(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,const FPRegister & fa)1903 void Assembler::fnmsub(const FPRegister& fd,
1904 const FPRegister& fn,
1905 const FPRegister& fm,
1906 const FPRegister& fa) {
1907 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d);
1908 }
1909
1910
fdiv(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1911 void Assembler::fdiv(const FPRegister& fd,
1912 const FPRegister& fn,
1913 const FPRegister& fm) {
1914 FPDataProcessing2Source(fd, fn, fm, FDIV);
1915 }
1916
1917
fmax(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1918 void Assembler::fmax(const FPRegister& fd,
1919 const FPRegister& fn,
1920 const FPRegister& fm) {
1921 FPDataProcessing2Source(fd, fn, fm, FMAX);
1922 }
1923
1924
fmaxnm(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1925 void Assembler::fmaxnm(const FPRegister& fd,
1926 const FPRegister& fn,
1927 const FPRegister& fm) {
1928 FPDataProcessing2Source(fd, fn, fm, FMAXNM);
1929 }
1930
1931
fmin(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1932 void Assembler::fmin(const FPRegister& fd,
1933 const FPRegister& fn,
1934 const FPRegister& fm) {
1935 FPDataProcessing2Source(fd, fn, fm, FMIN);
1936 }
1937
1938
fminnm(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm)1939 void Assembler::fminnm(const FPRegister& fd,
1940 const FPRegister& fn,
1941 const FPRegister& fm) {
1942 FPDataProcessing2Source(fd, fn, fm, FMINNM);
1943 }
1944
1945
fabs(const FPRegister & fd,const FPRegister & fn)1946 void Assembler::fabs(const FPRegister& fd,
1947 const FPRegister& fn) {
1948 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1949 FPDataProcessing1Source(fd, fn, FABS);
1950 }
1951
1952
fneg(const FPRegister & fd,const FPRegister & fn)1953 void Assembler::fneg(const FPRegister& fd,
1954 const FPRegister& fn) {
1955 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1956 FPDataProcessing1Source(fd, fn, FNEG);
1957 }
1958
1959
fsqrt(const FPRegister & fd,const FPRegister & fn)1960 void Assembler::fsqrt(const FPRegister& fd,
1961 const FPRegister& fn) {
1962 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1963 FPDataProcessing1Source(fd, fn, FSQRT);
1964 }
1965
1966
frinta(const FPRegister & fd,const FPRegister & fn)1967 void Assembler::frinta(const FPRegister& fd,
1968 const FPRegister& fn) {
1969 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1970 FPDataProcessing1Source(fd, fn, FRINTA);
1971 }
1972
1973
frintm(const FPRegister & fd,const FPRegister & fn)1974 void Assembler::frintm(const FPRegister& fd,
1975 const FPRegister& fn) {
1976 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1977 FPDataProcessing1Source(fd, fn, FRINTM);
1978 }
1979
1980
frintn(const FPRegister & fd,const FPRegister & fn)1981 void Assembler::frintn(const FPRegister& fd,
1982 const FPRegister& fn) {
1983 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1984 FPDataProcessing1Source(fd, fn, FRINTN);
1985 }
1986
1987
frintp(const FPRegister & fd,const FPRegister & fn)1988 void Assembler::frintp(const FPRegister& fd, const FPRegister& fn) {
1989 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1990 FPDataProcessing1Source(fd, fn, FRINTP);
1991 }
1992
1993
frintz(const FPRegister & fd,const FPRegister & fn)1994 void Assembler::frintz(const FPRegister& fd,
1995 const FPRegister& fn) {
1996 DCHECK(fd.SizeInBits() == fn.SizeInBits());
1997 FPDataProcessing1Source(fd, fn, FRINTZ);
1998 }
1999
2000
fcmp(const FPRegister & fn,const FPRegister & fm)2001 void Assembler::fcmp(const FPRegister& fn,
2002 const FPRegister& fm) {
2003 DCHECK(fn.SizeInBits() == fm.SizeInBits());
2004 Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn));
2005 }
2006
2007
fcmp(const FPRegister & fn,double value)2008 void Assembler::fcmp(const FPRegister& fn,
2009 double value) {
2010 USE(value);
2011 // Although the fcmp instruction can strictly only take an immediate value of
2012 // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't
2013 // affect the result of the comparison.
2014 DCHECK(value == 0.0);
2015 Emit(FPType(fn) | FCMP_zero | Rn(fn));
2016 }
2017
2018
fccmp(const FPRegister & fn,const FPRegister & fm,StatusFlags nzcv,Condition cond)2019 void Assembler::fccmp(const FPRegister& fn,
2020 const FPRegister& fm,
2021 StatusFlags nzcv,
2022 Condition cond) {
2023 DCHECK(fn.SizeInBits() == fm.SizeInBits());
2024 Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv));
2025 }
2026
2027
fcsel(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,Condition cond)2028 void Assembler::fcsel(const FPRegister& fd,
2029 const FPRegister& fn,
2030 const FPRegister& fm,
2031 Condition cond) {
2032 DCHECK(fd.SizeInBits() == fn.SizeInBits());
2033 DCHECK(fd.SizeInBits() == fm.SizeInBits());
2034 Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd));
2035 }
2036
2037
FPConvertToInt(const Register & rd,const FPRegister & fn,FPIntegerConvertOp op)2038 void Assembler::FPConvertToInt(const Register& rd,
2039 const FPRegister& fn,
2040 FPIntegerConvertOp op) {
2041 Emit(SF(rd) | FPType(fn) | op | Rn(fn) | Rd(rd));
2042 }
2043
2044
fcvt(const FPRegister & fd,const FPRegister & fn)2045 void Assembler::fcvt(const FPRegister& fd,
2046 const FPRegister& fn) {
2047 if (fd.Is64Bits()) {
2048 // Convert float to double.
2049 DCHECK(fn.Is32Bits());
2050 FPDataProcessing1Source(fd, fn, FCVT_ds);
2051 } else {
2052 // Convert double to float.
2053 DCHECK(fn.Is64Bits());
2054 FPDataProcessing1Source(fd, fn, FCVT_sd);
2055 }
2056 }
2057
2058
fcvtau(const Register & rd,const FPRegister & fn)2059 void Assembler::fcvtau(const Register& rd, const FPRegister& fn) {
2060 FPConvertToInt(rd, fn, FCVTAU);
2061 }
2062
2063
fcvtas(const Register & rd,const FPRegister & fn)2064 void Assembler::fcvtas(const Register& rd, const FPRegister& fn) {
2065 FPConvertToInt(rd, fn, FCVTAS);
2066 }
2067
2068
fcvtmu(const Register & rd,const FPRegister & fn)2069 void Assembler::fcvtmu(const Register& rd, const FPRegister& fn) {
2070 FPConvertToInt(rd, fn, FCVTMU);
2071 }
2072
2073
fcvtms(const Register & rd,const FPRegister & fn)2074 void Assembler::fcvtms(const Register& rd, const FPRegister& fn) {
2075 FPConvertToInt(rd, fn, FCVTMS);
2076 }
2077
2078
fcvtnu(const Register & rd,const FPRegister & fn)2079 void Assembler::fcvtnu(const Register& rd, const FPRegister& fn) {
2080 FPConvertToInt(rd, fn, FCVTNU);
2081 }
2082
2083
fcvtns(const Register & rd,const FPRegister & fn)2084 void Assembler::fcvtns(const Register& rd, const FPRegister& fn) {
2085 FPConvertToInt(rd, fn, FCVTNS);
2086 }
2087
2088
fcvtzu(const Register & rd,const FPRegister & fn)2089 void Assembler::fcvtzu(const Register& rd, const FPRegister& fn) {
2090 FPConvertToInt(rd, fn, FCVTZU);
2091 }
2092
2093
fcvtzs(const Register & rd,const FPRegister & fn)2094 void Assembler::fcvtzs(const Register& rd, const FPRegister& fn) {
2095 FPConvertToInt(rd, fn, FCVTZS);
2096 }
2097
2098
scvtf(const FPRegister & fd,const Register & rn,unsigned fbits)2099 void Assembler::scvtf(const FPRegister& fd,
2100 const Register& rn,
2101 unsigned fbits) {
2102 if (fbits == 0) {
2103 Emit(SF(rn) | FPType(fd) | SCVTF | Rn(rn) | Rd(fd));
2104 } else {
2105 Emit(SF(rn) | FPType(fd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
2106 Rd(fd));
2107 }
2108 }
2109
2110
ucvtf(const FPRegister & fd,const Register & rn,unsigned fbits)2111 void Assembler::ucvtf(const FPRegister& fd,
2112 const Register& rn,
2113 unsigned fbits) {
2114 if (fbits == 0) {
2115 Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd));
2116 } else {
2117 Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
2118 Rd(fd));
2119 }
2120 }
2121
2122
dcptr(Label * label)2123 void Assembler::dcptr(Label* label) {
2124 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2125 if (label->is_bound()) {
2126 // The label is bound, so it does not need to be updated and the internal
2127 // reference should be emitted.
2128 //
2129 // In this case, label->pos() returns the offset of the label from the
2130 // start of the buffer.
2131 internal_reference_positions_.push_back(pc_offset());
2132 dc64(reinterpret_cast<uintptr_t>(buffer_ + label->pos()));
2133 } else {
2134 int32_t offset;
2135 if (label->is_linked()) {
2136 // The label is linked, so the internal reference should be added
2137 // onto the end of the label's link chain.
2138 //
2139 // In this case, label->pos() returns the offset of the last linked
2140 // instruction from the start of the buffer.
2141 offset = label->pos() - pc_offset();
2142 DCHECK(offset != kStartOfLabelLinkChain);
2143 } else {
2144 // The label is unused, so it now becomes linked and the internal
2145 // reference is at the start of the new link chain.
2146 offset = kStartOfLabelLinkChain;
2147 }
2148 // The instruction at pc is now the last link in the label's chain.
2149 label->link_to(pc_offset());
2150
2151 // Traditionally the offset to the previous instruction in the chain is
2152 // encoded in the instruction payload (e.g. branch range) but internal
2153 // references are not instructions so while unbound they are encoded as
2154 // two consecutive brk instructions. The two 16-bit immediates are used
2155 // to encode the offset.
2156 offset >>= kInstructionSizeLog2;
2157 DCHECK(is_int32(offset));
2158 uint32_t high16 = unsigned_bitextract_32(31, 16, offset);
2159 uint32_t low16 = unsigned_bitextract_32(15, 0, offset);
2160
2161 brk(high16);
2162 brk(low16);
2163 }
2164 }
2165
2166
2167 // Note:
2168 // Below, a difference in case for the same letter indicates a
2169 // negated bit.
2170 // If b is 1, then B is 0.
ImmFP32(float imm)2171 Instr Assembler::ImmFP32(float imm) {
2172 DCHECK(IsImmFP32(imm));
2173 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
2174 uint32_t bits = float_to_rawbits(imm);
2175 // bit7: a000.0000
2176 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
2177 // bit6: 0b00.0000
2178 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
2179 // bit5_to_0: 00cd.efgh
2180 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
2181
2182 return (bit7 | bit6 | bit5_to_0) << ImmFP_offset;
2183 }
2184
2185
ImmFP64(double imm)2186 Instr Assembler::ImmFP64(double imm) {
2187 DCHECK(IsImmFP64(imm));
2188 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
2189 // 0000.0000.0000.0000.0000.0000.0000.0000
2190 uint64_t bits = double_to_rawbits(imm);
2191 // bit7: a000.0000
2192 uint64_t bit7 = ((bits >> 63) & 0x1) << 7;
2193 // bit6: 0b00.0000
2194 uint64_t bit6 = ((bits >> 61) & 0x1) << 6;
2195 // bit5_to_0: 00cd.efgh
2196 uint64_t bit5_to_0 = (bits >> 48) & 0x3f;
2197
2198 return static_cast<Instr>((bit7 | bit6 | bit5_to_0) << ImmFP_offset);
2199 }
2200
2201
2202 // Code generation helpers.
MoveWide(const Register & rd,uint64_t imm,int shift,MoveWideImmediateOp mov_op)2203 void Assembler::MoveWide(const Register& rd,
2204 uint64_t imm,
2205 int shift,
2206 MoveWideImmediateOp mov_op) {
2207 // Ignore the top 32 bits of an immediate if we're moving to a W register.
2208 if (rd.Is32Bits()) {
2209 // Check that the top 32 bits are zero (a positive 32-bit number) or top
2210 // 33 bits are one (a negative 32-bit number, sign extended to 64 bits).
2211 DCHECK(((imm >> kWRegSizeInBits) == 0) ||
2212 ((imm >> (kWRegSizeInBits - 1)) == 0x1ffffffff));
2213 imm &= kWRegMask;
2214 }
2215
2216 if (shift >= 0) {
2217 // Explicit shift specified.
2218 DCHECK((shift == 0) || (shift == 16) || (shift == 32) || (shift == 48));
2219 DCHECK(rd.Is64Bits() || (shift == 0) || (shift == 16));
2220 shift /= 16;
2221 } else {
2222 // Calculate a new immediate and shift combination to encode the immediate
2223 // argument.
2224 shift = 0;
2225 if ((imm & ~0xffffUL) == 0) {
2226 // Nothing to do.
2227 } else if ((imm & ~(0xffffUL << 16)) == 0) {
2228 imm >>= 16;
2229 shift = 1;
2230 } else if ((imm & ~(0xffffUL << 32)) == 0) {
2231 DCHECK(rd.Is64Bits());
2232 imm >>= 32;
2233 shift = 2;
2234 } else if ((imm & ~(0xffffUL << 48)) == 0) {
2235 DCHECK(rd.Is64Bits());
2236 imm >>= 48;
2237 shift = 3;
2238 }
2239 }
2240
2241 DCHECK(is_uint16(imm));
2242
2243 Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) |
2244 ImmMoveWide(static_cast<int>(imm)) | ShiftMoveWide(shift));
2245 }
2246
2247
AddSub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)2248 void Assembler::AddSub(const Register& rd,
2249 const Register& rn,
2250 const Operand& operand,
2251 FlagsUpdate S,
2252 AddSubOp op) {
2253 DCHECK(rd.SizeInBits() == rn.SizeInBits());
2254 DCHECK(!operand.NeedsRelocation(this));
2255 if (operand.IsImmediate()) {
2256 int64_t immediate = operand.ImmediateValue();
2257 DCHECK(IsImmAddSub(immediate));
2258 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
2259 Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |
2260 ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn));
2261 } else if (operand.IsShiftedRegister()) {
2262 DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
2263 DCHECK(operand.shift() != ROR);
2264
2265 // For instructions of the form:
2266 // add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ]
2267 // add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ]
2268 // add/sub wsp, wsp, <Wm> [, LSL #0-3 ]
2269 // adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]
2270 // or their 64-bit register equivalents, convert the operand from shifted to
2271 // extended register mode, and emit an add/sub extended instruction.
2272 if (rn.IsSP() || rd.IsSP()) {
2273 DCHECK(!(rd.IsSP() && (S == SetFlags)));
2274 DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S,
2275 AddSubExtendedFixed | op);
2276 } else {
2277 DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op);
2278 }
2279 } else {
2280 DCHECK(operand.IsExtendedRegister());
2281 DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op);
2282 }
2283 }
2284
2285
AddSubWithCarry(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)2286 void Assembler::AddSubWithCarry(const Register& rd,
2287 const Register& rn,
2288 const Operand& operand,
2289 FlagsUpdate S,
2290 AddSubWithCarryOp op) {
2291 DCHECK(rd.SizeInBits() == rn.SizeInBits());
2292 DCHECK(rd.SizeInBits() == operand.reg().SizeInBits());
2293 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
2294 DCHECK(!operand.NeedsRelocation(this));
2295 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd));
2296 }
2297
2298
hlt(int code)2299 void Assembler::hlt(int code) {
2300 DCHECK(is_uint16(code));
2301 Emit(HLT | ImmException(code));
2302 }
2303
2304
brk(int code)2305 void Assembler::brk(int code) {
2306 DCHECK(is_uint16(code));
2307 Emit(BRK | ImmException(code));
2308 }
2309
2310
EmitStringData(const char * string)2311 void Assembler::EmitStringData(const char* string) {
2312 size_t len = strlen(string) + 1;
2313 DCHECK(RoundUp(len, kInstructionSize) <= static_cast<size_t>(kGap));
2314 EmitData(string, static_cast<int>(len));
2315 // Pad with NULL characters until pc_ is aligned.
2316 const char pad[] = {'\0', '\0', '\0', '\0'};
2317 STATIC_ASSERT(sizeof(pad) == kInstructionSize);
2318 EmitData(pad, RoundUp(pc_offset(), kInstructionSize) - pc_offset());
2319 }
2320
2321
debug(const char * message,uint32_t code,Instr params)2322 void Assembler::debug(const char* message, uint32_t code, Instr params) {
2323 #ifdef USE_SIMULATOR
2324 // Don't generate simulator specific code if we are building a snapshot, which
2325 // might be run on real hardware.
2326 if (!serializer_enabled()) {
2327 // The arguments to the debug marker need to be contiguous in memory, so
2328 // make sure we don't try to emit pools.
2329 BlockPoolsScope scope(this);
2330
2331 Label start;
2332 bind(&start);
2333
2334 // Refer to instructions-arm64.h for a description of the marker and its
2335 // arguments.
2336 hlt(kImmExceptionIsDebug);
2337 DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugCodeOffset);
2338 dc32(code);
2339 DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugParamsOffset);
2340 dc32(params);
2341 DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugMessageOffset);
2342 EmitStringData(message);
2343 hlt(kImmExceptionIsUnreachable);
2344
2345 return;
2346 }
2347 // Fall through if Serializer is enabled.
2348 #endif
2349
2350 if (params & BREAK) {
2351 hlt(kImmExceptionIsDebug);
2352 }
2353 }
2354
2355
Logical(const Register & rd,const Register & rn,const Operand & operand,LogicalOp op)2356 void Assembler::Logical(const Register& rd,
2357 const Register& rn,
2358 const Operand& operand,
2359 LogicalOp op) {
2360 DCHECK(rd.SizeInBits() == rn.SizeInBits());
2361 DCHECK(!operand.NeedsRelocation(this));
2362 if (operand.IsImmediate()) {
2363 int64_t immediate = operand.ImmediateValue();
2364 unsigned reg_size = rd.SizeInBits();
2365
2366 DCHECK(immediate != 0);
2367 DCHECK(immediate != -1);
2368 DCHECK(rd.Is64Bits() || is_uint32(immediate));
2369
2370 // If the operation is NOT, invert the operation and immediate.
2371 if ((op & NOT) == NOT) {
2372 op = static_cast<LogicalOp>(op & ~NOT);
2373 immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);
2374 }
2375
2376 unsigned n, imm_s, imm_r;
2377 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
2378 // Immediate can be encoded in the instruction.
2379 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
2380 } else {
2381 // This case is handled in the macro assembler.
2382 UNREACHABLE();
2383 }
2384 } else {
2385 DCHECK(operand.IsShiftedRegister());
2386 DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
2387 Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed);
2388 DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);
2389 }
2390 }
2391
2392
LogicalImmediate(const Register & rd,const Register & rn,unsigned n,unsigned imm_s,unsigned imm_r,LogicalOp op)2393 void Assembler::LogicalImmediate(const Register& rd,
2394 const Register& rn,
2395 unsigned n,
2396 unsigned imm_s,
2397 unsigned imm_r,
2398 LogicalOp op) {
2399 unsigned reg_size = rd.SizeInBits();
2400 Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);
2401 Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |
2402 ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |
2403 Rn(rn));
2404 }
2405
2406
ConditionalCompare(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)2407 void Assembler::ConditionalCompare(const Register& rn,
2408 const Operand& operand,
2409 StatusFlags nzcv,
2410 Condition cond,
2411 ConditionalCompareOp op) {
2412 Instr ccmpop;
2413 DCHECK(!operand.NeedsRelocation(this));
2414 if (operand.IsImmediate()) {
2415 int64_t immediate = operand.ImmediateValue();
2416 DCHECK(IsImmConditionalCompare(immediate));
2417 ccmpop = ConditionalCompareImmediateFixed | op |
2418 ImmCondCmp(static_cast<unsigned>(immediate));
2419 } else {
2420 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
2421 ccmpop = ConditionalCompareRegisterFixed | op | Rm(operand.reg());
2422 }
2423 Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));
2424 }
2425
2426
DataProcessing1Source(const Register & rd,const Register & rn,DataProcessing1SourceOp op)2427 void Assembler::DataProcessing1Source(const Register& rd,
2428 const Register& rn,
2429 DataProcessing1SourceOp op) {
2430 DCHECK(rd.SizeInBits() == rn.SizeInBits());
2431 Emit(SF(rn) | op | Rn(rn) | Rd(rd));
2432 }
2433
2434
FPDataProcessing1Source(const FPRegister & fd,const FPRegister & fn,FPDataProcessing1SourceOp op)2435 void Assembler::FPDataProcessing1Source(const FPRegister& fd,
2436 const FPRegister& fn,
2437 FPDataProcessing1SourceOp op) {
2438 Emit(FPType(fn) | op | Rn(fn) | Rd(fd));
2439 }
2440
2441
FPDataProcessing2Source(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,FPDataProcessing2SourceOp op)2442 void Assembler::FPDataProcessing2Source(const FPRegister& fd,
2443 const FPRegister& fn,
2444 const FPRegister& fm,
2445 FPDataProcessing2SourceOp op) {
2446 DCHECK(fd.SizeInBits() == fn.SizeInBits());
2447 DCHECK(fd.SizeInBits() == fm.SizeInBits());
2448 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd));
2449 }
2450
2451
FPDataProcessing3Source(const FPRegister & fd,const FPRegister & fn,const FPRegister & fm,const FPRegister & fa,FPDataProcessing3SourceOp op)2452 void Assembler::FPDataProcessing3Source(const FPRegister& fd,
2453 const FPRegister& fn,
2454 const FPRegister& fm,
2455 const FPRegister& fa,
2456 FPDataProcessing3SourceOp op) {
2457 DCHECK(AreSameSizeAndType(fd, fn, fm, fa));
2458 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa));
2459 }
2460
2461
EmitShift(const Register & rd,const Register & rn,Shift shift,unsigned shift_amount)2462 void Assembler::EmitShift(const Register& rd,
2463 const Register& rn,
2464 Shift shift,
2465 unsigned shift_amount) {
2466 switch (shift) {
2467 case LSL:
2468 lsl(rd, rn, shift_amount);
2469 break;
2470 case LSR:
2471 lsr(rd, rn, shift_amount);
2472 break;
2473 case ASR:
2474 asr(rd, rn, shift_amount);
2475 break;
2476 case ROR:
2477 ror(rd, rn, shift_amount);
2478 break;
2479 default:
2480 UNREACHABLE();
2481 }
2482 }
2483
2484
EmitExtendShift(const Register & rd,const Register & rn,Extend extend,unsigned left_shift)2485 void Assembler::EmitExtendShift(const Register& rd,
2486 const Register& rn,
2487 Extend extend,
2488 unsigned left_shift) {
2489 DCHECK(rd.SizeInBits() >= rn.SizeInBits());
2490 unsigned reg_size = rd.SizeInBits();
2491 // Use the correct size of register.
2492 Register rn_ = Register::Create(rn.code(), rd.SizeInBits());
2493 // Bits extracted are high_bit:0.
2494 unsigned high_bit = (8 << (extend & 0x3)) - 1;
2495 // Number of bits left in the result that are not introduced by the shift.
2496 unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);
2497
2498 if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {
2499 switch (extend) {
2500 case UXTB:
2501 case UXTH:
2502 case UXTW: ubfm(rd, rn_, non_shift_bits, high_bit); break;
2503 case SXTB:
2504 case SXTH:
2505 case SXTW: sbfm(rd, rn_, non_shift_bits, high_bit); break;
2506 case UXTX:
2507 case SXTX: {
2508 DCHECK(rn.SizeInBits() == kXRegSizeInBits);
2509 // Nothing to extend. Just shift.
2510 lsl(rd, rn_, left_shift);
2511 break;
2512 }
2513 default: UNREACHABLE();
2514 }
2515 } else {
2516 // No need to extend as the extended bits would be shifted away.
2517 lsl(rd, rn_, left_shift);
2518 }
2519 }
2520
2521
DataProcShiftedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)2522 void Assembler::DataProcShiftedRegister(const Register& rd,
2523 const Register& rn,
2524 const Operand& operand,
2525 FlagsUpdate S,
2526 Instr op) {
2527 DCHECK(operand.IsShiftedRegister());
2528 DCHECK(rn.Is64Bits() || (rn.Is32Bits() && is_uint5(operand.shift_amount())));
2529 DCHECK(!operand.NeedsRelocation(this));
2530 Emit(SF(rd) | op | Flags(S) |
2531 ShiftDP(operand.shift()) | ImmDPShift(operand.shift_amount()) |
2532 Rm(operand.reg()) | Rn(rn) | Rd(rd));
2533 }
2534
2535
DataProcExtendedRegister(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,Instr op)2536 void Assembler::DataProcExtendedRegister(const Register& rd,
2537 const Register& rn,
2538 const Operand& operand,
2539 FlagsUpdate S,
2540 Instr op) {
2541 DCHECK(!operand.NeedsRelocation(this));
2542 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
2543 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) |
2544 ExtendMode(operand.extend()) | ImmExtendShift(operand.shift_amount()) |
2545 dest_reg | RnSP(rn));
2546 }
2547
2548
IsImmAddSub(int64_t immediate)2549 bool Assembler::IsImmAddSub(int64_t immediate) {
2550 return is_uint12(immediate) ||
2551 (is_uint12(immediate >> 12) && ((immediate & 0xfff) == 0));
2552 }
2553
LoadStore(const CPURegister & rt,const MemOperand & addr,LoadStoreOp op)2554 void Assembler::LoadStore(const CPURegister& rt,
2555 const MemOperand& addr,
2556 LoadStoreOp op) {
2557 Instr memop = op | Rt(rt) | RnSP(addr.base());
2558
2559 if (addr.IsImmediateOffset()) {
2560 LSDataSize size = CalcLSDataSize(op);
2561 if (IsImmLSScaled(addr.offset(), size)) {
2562 int offset = static_cast<int>(addr.offset());
2563 // Use the scaled addressing mode.
2564 Emit(LoadStoreUnsignedOffsetFixed | memop |
2565 ImmLSUnsigned(offset >> size));
2566 } else if (IsImmLSUnscaled(addr.offset())) {
2567 int offset = static_cast<int>(addr.offset());
2568 // Use the unscaled addressing mode.
2569 Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset));
2570 } else {
2571 // This case is handled in the macro assembler.
2572 UNREACHABLE();
2573 }
2574 } else if (addr.IsRegisterOffset()) {
2575 Extend ext = addr.extend();
2576 Shift shift = addr.shift();
2577 unsigned shift_amount = addr.shift_amount();
2578
2579 // LSL is encoded in the option field as UXTX.
2580 if (shift == LSL) {
2581 ext = UXTX;
2582 }
2583
2584 // Shifts are encoded in one bit, indicating a left shift by the memory
2585 // access size.
2586 DCHECK((shift_amount == 0) ||
2587 (shift_amount == static_cast<unsigned>(CalcLSDataSize(op))));
2588 Emit(LoadStoreRegisterOffsetFixed | memop | Rm(addr.regoffset()) |
2589 ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0));
2590 } else {
2591 // Pre-index and post-index modes.
2592 DCHECK(!rt.Is(addr.base()));
2593 if (IsImmLSUnscaled(addr.offset())) {
2594 int offset = static_cast<int>(addr.offset());
2595 if (addr.IsPreIndex()) {
2596 Emit(LoadStorePreIndexFixed | memop | ImmLS(offset));
2597 } else {
2598 DCHECK(addr.IsPostIndex());
2599 Emit(LoadStorePostIndexFixed | memop | ImmLS(offset));
2600 }
2601 } else {
2602 // This case is handled in the macro assembler.
2603 UNREACHABLE();
2604 }
2605 }
2606 }
2607
2608
IsImmLSUnscaled(int64_t offset)2609 bool Assembler::IsImmLSUnscaled(int64_t offset) {
2610 return is_int9(offset);
2611 }
2612
2613
IsImmLSScaled(int64_t offset,LSDataSize size)2614 bool Assembler::IsImmLSScaled(int64_t offset, LSDataSize size) {
2615 bool offset_is_size_multiple = (((offset >> size) << size) == offset);
2616 return offset_is_size_multiple && is_uint12(offset >> size);
2617 }
2618
2619
IsImmLSPair(int64_t offset,LSDataSize size)2620 bool Assembler::IsImmLSPair(int64_t offset, LSDataSize size) {
2621 bool offset_is_size_multiple = (((offset >> size) << size) == offset);
2622 return offset_is_size_multiple && is_int7(offset >> size);
2623 }
2624
2625
IsImmLLiteral(int64_t offset)2626 bool Assembler::IsImmLLiteral(int64_t offset) {
2627 int inst_size = static_cast<int>(kInstructionSizeLog2);
2628 bool offset_is_inst_multiple =
2629 (((offset >> inst_size) << inst_size) == offset);
2630 return offset_is_inst_multiple && is_intn(offset, ImmLLiteral_width);
2631 }
2632
2633
2634 // Test if a given value can be encoded in the immediate field of a logical
2635 // instruction.
2636 // If it can be encoded, the function returns true, and values pointed to by n,
2637 // imm_s and imm_r are updated with immediates encoded in the format required
2638 // by the corresponding fields in the logical instruction.
2639 // If it can not be encoded, the function returns false, and the values pointed
2640 // to by n, imm_s and imm_r are undefined.
IsImmLogical(uint64_t value,unsigned width,unsigned * n,unsigned * imm_s,unsigned * imm_r)2641 bool Assembler::IsImmLogical(uint64_t value,
2642 unsigned width,
2643 unsigned* n,
2644 unsigned* imm_s,
2645 unsigned* imm_r) {
2646 DCHECK((n != NULL) && (imm_s != NULL) && (imm_r != NULL));
2647 DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
2648
2649 bool negate = false;
2650
2651 // Logical immediates are encoded using parameters n, imm_s and imm_r using
2652 // the following table:
2653 //
2654 // N imms immr size S R
2655 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
2656 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
2657 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
2658 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
2659 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
2660 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
2661 // (s bits must not be all set)
2662 //
2663 // A pattern is constructed of size bits, where the least significant S+1 bits
2664 // are set. The pattern is rotated right by R, and repeated across a 32 or
2665 // 64-bit value, depending on destination register width.
2666 //
2667 // Put another way: the basic format of a logical immediate is a single
2668 // contiguous stretch of 1 bits, repeated across the whole word at intervals
2669 // given by a power of 2. To identify them quickly, we first locate the
2670 // lowest stretch of 1 bits, then the next 1 bit above that; that combination
2671 // is different for every logical immediate, so it gives us all the
2672 // information we need to identify the only logical immediate that our input
2673 // could be, and then we simply check if that's the value we actually have.
2674 //
2675 // (The rotation parameter does give the possibility of the stretch of 1 bits
2676 // going 'round the end' of the word. To deal with that, we observe that in
2677 // any situation where that happens the bitwise NOT of the value is also a
2678 // valid logical immediate. So we simply invert the input whenever its low bit
2679 // is set, and then we know that the rotated case can't arise.)
2680
2681 if (value & 1) {
2682 // If the low bit is 1, negate the value, and set a flag to remember that we
2683 // did (so that we can adjust the return values appropriately).
2684 negate = true;
2685 value = ~value;
2686 }
2687
2688 if (width == kWRegSizeInBits) {
2689 // To handle 32-bit logical immediates, the very easiest thing is to repeat
2690 // the input value twice to make a 64-bit word. The correct encoding of that
2691 // as a logical immediate will also be the correct encoding of the 32-bit
2692 // value.
2693
2694 // The most-significant 32 bits may not be zero (ie. negate is true) so
2695 // shift the value left before duplicating it.
2696 value <<= kWRegSizeInBits;
2697 value |= value >> kWRegSizeInBits;
2698 }
2699
2700 // The basic analysis idea: imagine our input word looks like this.
2701 //
2702 // 0011111000111110001111100011111000111110001111100011111000111110
2703 // c b a
2704 // |<--d-->|
2705 //
2706 // We find the lowest set bit (as an actual power-of-2 value, not its index)
2707 // and call it a. Then we add a to our original number, which wipes out the
2708 // bottommost stretch of set bits and replaces it with a 1 carried into the
2709 // next zero bit. Then we look for the new lowest set bit, which is in
2710 // position b, and subtract it, so now our number is just like the original
2711 // but with the lowest stretch of set bits completely gone. Now we find the
2712 // lowest set bit again, which is position c in the diagram above. Then we'll
2713 // measure the distance d between bit positions a and c (using CLZ), and that
2714 // tells us that the only valid logical immediate that could possibly be equal
2715 // to this number is the one in which a stretch of bits running from a to just
2716 // below b is replicated every d bits.
2717 uint64_t a = LargestPowerOf2Divisor(value);
2718 uint64_t value_plus_a = value + a;
2719 uint64_t b = LargestPowerOf2Divisor(value_plus_a);
2720 uint64_t value_plus_a_minus_b = value_plus_a - b;
2721 uint64_t c = LargestPowerOf2Divisor(value_plus_a_minus_b);
2722
2723 int d, clz_a, out_n;
2724 uint64_t mask;
2725
2726 if (c != 0) {
2727 // The general case, in which there is more than one stretch of set bits.
2728 // Compute the repeat distance d, and set up a bitmask covering the basic
2729 // unit of repetition (i.e. a word with the bottom d bits set). Also, in all
2730 // of these cases the N bit of the output will be zero.
2731 clz_a = CountLeadingZeros(a, kXRegSizeInBits);
2732 int clz_c = CountLeadingZeros(c, kXRegSizeInBits);
2733 d = clz_a - clz_c;
2734 mask = ((V8_UINT64_C(1) << d) - 1);
2735 out_n = 0;
2736 } else {
2737 // Handle degenerate cases.
2738 //
2739 // If any of those 'find lowest set bit' operations didn't find a set bit at
2740 // all, then the word will have been zero thereafter, so in particular the
2741 // last lowest_set_bit operation will have returned zero. So we can test for
2742 // all the special case conditions in one go by seeing if c is zero.
2743 if (a == 0) {
2744 // The input was zero (or all 1 bits, which will come to here too after we
2745 // inverted it at the start of the function), for which we just return
2746 // false.
2747 return false;
2748 } else {
2749 // Otherwise, if c was zero but a was not, then there's just one stretch
2750 // of set bits in our word, meaning that we have the trivial case of
2751 // d == 64 and only one 'repetition'. Set up all the same variables as in
2752 // the general case above, and set the N bit in the output.
2753 clz_a = CountLeadingZeros(a, kXRegSizeInBits);
2754 d = 64;
2755 mask = ~V8_UINT64_C(0);
2756 out_n = 1;
2757 }
2758 }
2759
2760 // If the repeat period d is not a power of two, it can't be encoded.
2761 if (!IS_POWER_OF_TWO(d)) {
2762 return false;
2763 }
2764
2765 if (((b - a) & ~mask) != 0) {
2766 // If the bit stretch (b - a) does not fit within the mask derived from the
2767 // repeat period, then fail.
2768 return false;
2769 }
2770
2771 // The only possible option is b - a repeated every d bits. Now we're going to
2772 // actually construct the valid logical immediate derived from that
2773 // specification, and see if it equals our original input.
2774 //
2775 // To repeat a value every d bits, we multiply it by a number of the form
2776 // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
2777 // be derived using a table lookup on CLZ(d).
2778 static const uint64_t multipliers[] = {
2779 0x0000000000000001UL,
2780 0x0000000100000001UL,
2781 0x0001000100010001UL,
2782 0x0101010101010101UL,
2783 0x1111111111111111UL,
2784 0x5555555555555555UL,
2785 };
2786 int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57;
2787 // Ensure that the index to the multipliers array is within bounds.
2788 DCHECK((multiplier_idx >= 0) &&
2789 (static_cast<size_t>(multiplier_idx) < arraysize(multipliers)));
2790 uint64_t multiplier = multipliers[multiplier_idx];
2791 uint64_t candidate = (b - a) * multiplier;
2792
2793 if (value != candidate) {
2794 // The candidate pattern doesn't match our input value, so fail.
2795 return false;
2796 }
2797
2798 // We have a match! This is a valid logical immediate, so now we have to
2799 // construct the bits and pieces of the instruction encoding that generates
2800 // it.
2801
2802 // Count the set bits in our basic stretch. The special case of clz(0) == -1
2803 // makes the answer come out right for stretches that reach the very top of
2804 // the word (e.g. numbers like 0xffffc00000000000).
2805 int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSizeInBits);
2806 int s = clz_a - clz_b;
2807
2808 // Decide how many bits to rotate right by, to put the low bit of that basic
2809 // stretch in position a.
2810 int r;
2811 if (negate) {
2812 // If we inverted the input right at the start of this function, here's
2813 // where we compensate: the number of set bits becomes the number of clear
2814 // bits, and the rotation count is based on position b rather than position
2815 // a (since b is the location of the 'lowest' 1 bit after inversion).
2816 s = d - s;
2817 r = (clz_b + 1) & (d - 1);
2818 } else {
2819 r = (clz_a + 1) & (d - 1);
2820 }
2821
2822 // Now we're done, except for having to encode the S output in such a way that
2823 // it gives both the number of set bits and the length of the repeated
2824 // segment. The s field is encoded like this:
2825 //
2826 // imms size S
2827 // ssssss 64 UInt(ssssss)
2828 // 0sssss 32 UInt(sssss)
2829 // 10ssss 16 UInt(ssss)
2830 // 110sss 8 UInt(sss)
2831 // 1110ss 4 UInt(ss)
2832 // 11110s 2 UInt(s)
2833 //
2834 // So we 'or' (-d << 1) with our computed s to form imms.
2835 *n = out_n;
2836 *imm_s = ((-d << 1) | (s - 1)) & 0x3f;
2837 *imm_r = r;
2838
2839 return true;
2840 }
2841
2842
IsImmConditionalCompare(int64_t immediate)2843 bool Assembler::IsImmConditionalCompare(int64_t immediate) {
2844 return is_uint5(immediate);
2845 }
2846
2847
IsImmFP32(float imm)2848 bool Assembler::IsImmFP32(float imm) {
2849 // Valid values will have the form:
2850 // aBbb.bbbc.defg.h000.0000.0000.0000.0000
2851 uint32_t bits = float_to_rawbits(imm);
2852 // bits[19..0] are cleared.
2853 if ((bits & 0x7ffff) != 0) {
2854 return false;
2855 }
2856
2857 // bits[29..25] are all set or all cleared.
2858 uint32_t b_pattern = (bits >> 16) & 0x3e00;
2859 if (b_pattern != 0 && b_pattern != 0x3e00) {
2860 return false;
2861 }
2862
2863 // bit[30] and bit[29] are opposite.
2864 if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
2865 return false;
2866 }
2867
2868 return true;
2869 }
2870
2871
IsImmFP64(double imm)2872 bool Assembler::IsImmFP64(double imm) {
2873 // Valid values will have the form:
2874 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
2875 // 0000.0000.0000.0000.0000.0000.0000.0000
2876 uint64_t bits = double_to_rawbits(imm);
2877 // bits[47..0] are cleared.
2878 if ((bits & 0xffffffffffffL) != 0) {
2879 return false;
2880 }
2881
2882 // bits[61..54] are all set or all cleared.
2883 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
2884 if (b_pattern != 0 && b_pattern != 0x3fc0) {
2885 return false;
2886 }
2887
2888 // bit[62] and bit[61] are opposite.
2889 if (((bits ^ (bits << 1)) & 0x4000000000000000L) == 0) {
2890 return false;
2891 }
2892
2893 return true;
2894 }
2895
2896
GrowBuffer()2897 void Assembler::GrowBuffer() {
2898 if (!own_buffer_) FATAL("external code buffer is too small");
2899
2900 // Compute new buffer size.
2901 CodeDesc desc; // the new buffer
2902 if (buffer_size_ < 1 * MB) {
2903 desc.buffer_size = 2 * buffer_size_;
2904 } else {
2905 desc.buffer_size = buffer_size_ + 1 * MB;
2906 }
2907 CHECK_GT(desc.buffer_size, 0); // No overflow.
2908
2909 byte* buffer = reinterpret_cast<byte*>(buffer_);
2910
2911 // Set up new buffer.
2912 desc.buffer = NewArray<byte>(desc.buffer_size);
2913 desc.origin = this;
2914
2915 desc.instr_size = pc_offset();
2916 desc.reloc_size =
2917 static_cast<int>((buffer + buffer_size_) - reloc_info_writer.pos());
2918
2919 // Copy the data.
2920 intptr_t pc_delta = desc.buffer - buffer;
2921 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
2922 (buffer + buffer_size_);
2923 memmove(desc.buffer, buffer, desc.instr_size);
2924 memmove(reloc_info_writer.pos() + rc_delta,
2925 reloc_info_writer.pos(), desc.reloc_size);
2926
2927 // Switch buffers.
2928 DeleteArray(buffer_);
2929 buffer_ = desc.buffer;
2930 buffer_size_ = desc.buffer_size;
2931 pc_ = reinterpret_cast<byte*>(pc_) + pc_delta;
2932 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2933 reloc_info_writer.last_pc() + pc_delta);
2934
2935 // None of our relocation types are pc relative pointing outside the code
2936 // buffer nor pc absolute pointing inside the code buffer, so there is no need
2937 // to relocate any emitted relocation entries.
2938
2939 // Relocate internal references.
2940 for (auto pos : internal_reference_positions_) {
2941 intptr_t* p = reinterpret_cast<intptr_t*>(buffer_ + pos);
2942 *p += pc_delta;
2943 }
2944
2945 // Pending relocation entries are also relative, no need to relocate.
2946 }
2947
2948
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)2949 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2950 // We do not try to reuse pool constants.
2951 RelocInfo rinfo(isolate(), reinterpret_cast<byte*>(pc_), rmode, data, NULL);
2952 if (((rmode >= RelocInfo::COMMENT) &&
2953 (rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL)) ||
2954 (rmode == RelocInfo::INTERNAL_REFERENCE) ||
2955 (rmode == RelocInfo::CONST_POOL) || (rmode == RelocInfo::VENEER_POOL) ||
2956 (rmode == RelocInfo::DEOPT_SCRIPT_OFFSET) ||
2957 (rmode == RelocInfo::DEOPT_INLINING_ID) ||
2958 (rmode == RelocInfo::DEOPT_REASON) || (rmode == RelocInfo::DEOPT_ID)) {
2959 // Adjust code for new modes.
2960 DCHECK(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsComment(rmode) ||
2961 RelocInfo::IsDeoptReason(rmode) || RelocInfo::IsDeoptId(rmode) ||
2962 RelocInfo::IsDeoptPosition(rmode) ||
2963 RelocInfo::IsInternalReference(rmode) ||
2964 RelocInfo::IsConstPool(rmode) || RelocInfo::IsVeneerPool(rmode));
2965 // These modes do not need an entry in the constant pool.
2966 } else {
2967 constpool_.RecordEntry(data, rmode);
2968 // Make sure the constant pool is not emitted in place of the next
2969 // instruction for which we just recorded relocation info.
2970 BlockConstPoolFor(1);
2971 }
2972
2973 if (!RelocInfo::IsNone(rmode)) {
2974 // Don't record external references unless the heap will be serialized.
2975 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2976 !serializer_enabled() && !emit_debug_code()) {
2977 return;
2978 }
2979 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2980 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2981 RelocInfo reloc_info_with_ast_id(isolate(), reinterpret_cast<byte*>(pc_),
2982 rmode, RecordedAstId().ToInt(), NULL);
2983 ClearRecordedAstId();
2984 reloc_info_writer.Write(&reloc_info_with_ast_id);
2985 } else {
2986 reloc_info_writer.Write(&rinfo);
2987 }
2988 }
2989 }
2990
2991
BlockConstPoolFor(int instructions)2992 void Assembler::BlockConstPoolFor(int instructions) {
2993 int pc_limit = pc_offset() + instructions * kInstructionSize;
2994 if (no_const_pool_before_ < pc_limit) {
2995 no_const_pool_before_ = pc_limit;
2996 // Make sure the pool won't be blocked for too long.
2997 DCHECK(pc_limit < constpool_.MaxPcOffset());
2998 }
2999
3000 if (next_constant_pool_check_ < no_const_pool_before_) {
3001 next_constant_pool_check_ = no_const_pool_before_;
3002 }
3003 }
3004
3005
CheckConstPool(bool force_emit,bool require_jump)3006 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
3007 // Some short sequence of instruction mustn't be broken up by constant pool
3008 // emission, such sequences are protected by calls to BlockConstPoolFor and
3009 // BlockConstPoolScope.
3010 if (is_const_pool_blocked()) {
3011 // Something is wrong if emission is forced and blocked at the same time.
3012 DCHECK(!force_emit);
3013 return;
3014 }
3015
3016 // There is nothing to do if there are no pending constant pool entries.
3017 if (constpool_.IsEmpty()) {
3018 // Calculate the offset of the next check.
3019 SetNextConstPoolCheckIn(kCheckConstPoolInterval);
3020 return;
3021 }
3022
3023 // We emit a constant pool when:
3024 // * requested to do so by parameter force_emit (e.g. after each function).
3025 // * the distance to the first instruction accessing the constant pool is
3026 // kApproxMaxDistToConstPool or more.
3027 // * the number of entries in the pool is kApproxMaxPoolEntryCount or more.
3028 int dist = constpool_.DistanceToFirstUse();
3029 int count = constpool_.EntryCount();
3030 if (!force_emit &&
3031 (dist < kApproxMaxDistToConstPool) &&
3032 (count < kApproxMaxPoolEntryCount)) {
3033 return;
3034 }
3035
3036
3037 // Emit veneers for branches that would go out of range during emission of the
3038 // constant pool.
3039 int worst_case_size = constpool_.WorstCaseSize();
3040 CheckVeneerPool(false, require_jump,
3041 kVeneerDistanceMargin + worst_case_size);
3042
3043 // Check that the code buffer is large enough before emitting the constant
3044 // pool (this includes the gap to the relocation information).
3045 int needed_space = worst_case_size + kGap + 1 * kInstructionSize;
3046 while (buffer_space() <= needed_space) {
3047 GrowBuffer();
3048 }
3049
3050 Label size_check;
3051 bind(&size_check);
3052 constpool_.Emit(require_jump);
3053 DCHECK(SizeOfCodeGeneratedSince(&size_check) <=
3054 static_cast<unsigned>(worst_case_size));
3055
3056 // Since a constant pool was just emitted, move the check offset forward by
3057 // the standard interval.
3058 SetNextConstPoolCheckIn(kCheckConstPoolInterval);
3059 }
3060
3061
ShouldEmitVeneer(int max_reachable_pc,int margin)3062 bool Assembler::ShouldEmitVeneer(int max_reachable_pc, int margin) {
3063 // Account for the branch around the veneers and the guard.
3064 int protection_offset = 2 * kInstructionSize;
3065 return pc_offset() > max_reachable_pc - margin - protection_offset -
3066 static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize);
3067 }
3068
3069
RecordVeneerPool(int location_offset,int size)3070 void Assembler::RecordVeneerPool(int location_offset, int size) {
3071 RelocInfo rinfo(isolate(), buffer_ + location_offset, RelocInfo::VENEER_POOL,
3072 static_cast<intptr_t>(size), NULL);
3073 reloc_info_writer.Write(&rinfo);
3074 }
3075
3076
EmitVeneers(bool force_emit,bool need_protection,int margin)3077 void Assembler::EmitVeneers(bool force_emit, bool need_protection, int margin) {
3078 BlockPoolsScope scope(this);
3079 RecordComment("[ Veneers");
3080
3081 // The exact size of the veneer pool must be recorded (see the comment at the
3082 // declaration site of RecordConstPool()), but computing the number of
3083 // veneers that will be generated is not obvious. So instead we remember the
3084 // current position and will record the size after the pool has been
3085 // generated.
3086 Label size_check;
3087 bind(&size_check);
3088 int veneer_pool_relocinfo_loc = pc_offset();
3089
3090 Label end;
3091 if (need_protection) {
3092 b(&end);
3093 }
3094
3095 EmitVeneersGuard();
3096
3097 Label veneer_size_check;
3098
3099 std::multimap<int, FarBranchInfo>::iterator it, it_to_delete;
3100
3101 it = unresolved_branches_.begin();
3102 while (it != unresolved_branches_.end()) {
3103 if (force_emit || ShouldEmitVeneer(it->first, margin)) {
3104 Instruction* branch = InstructionAt(it->second.pc_offset_);
3105 Label* label = it->second.label_;
3106
3107 #ifdef DEBUG
3108 bind(&veneer_size_check);
3109 #endif
3110 // Patch the branch to point to the current position, and emit a branch
3111 // to the label.
3112 Instruction* veneer = reinterpret_cast<Instruction*>(pc_);
3113 RemoveBranchFromLabelLinkChain(branch, label, veneer);
3114 branch->SetImmPCOffsetTarget(isolate(), veneer);
3115 b(label);
3116 #ifdef DEBUG
3117 DCHECK(SizeOfCodeGeneratedSince(&veneer_size_check) <=
3118 static_cast<uint64_t>(kMaxVeneerCodeSize));
3119 veneer_size_check.Unuse();
3120 #endif
3121
3122 it_to_delete = it++;
3123 unresolved_branches_.erase(it_to_delete);
3124 } else {
3125 ++it;
3126 }
3127 }
3128
3129 // Record the veneer pool size.
3130 int pool_size = static_cast<int>(SizeOfCodeGeneratedSince(&size_check));
3131 RecordVeneerPool(veneer_pool_relocinfo_loc, pool_size);
3132
3133 if (unresolved_branches_.empty()) {
3134 next_veneer_pool_check_ = kMaxInt;
3135 } else {
3136 next_veneer_pool_check_ =
3137 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
3138 }
3139
3140 bind(&end);
3141
3142 RecordComment("]");
3143 }
3144
3145
CheckVeneerPool(bool force_emit,bool require_jump,int margin)3146 void Assembler::CheckVeneerPool(bool force_emit, bool require_jump,
3147 int margin) {
3148 // There is nothing to do if there are no pending veneer pool entries.
3149 if (unresolved_branches_.empty()) {
3150 DCHECK(next_veneer_pool_check_ == kMaxInt);
3151 return;
3152 }
3153
3154 DCHECK(pc_offset() < unresolved_branches_first_limit());
3155
3156 // Some short sequence of instruction mustn't be broken up by veneer pool
3157 // emission, such sequences are protected by calls to BlockVeneerPoolFor and
3158 // BlockVeneerPoolScope.
3159 if (is_veneer_pool_blocked()) {
3160 DCHECK(!force_emit);
3161 return;
3162 }
3163
3164 if (!require_jump) {
3165 // Prefer emitting veneers protected by an existing instruction.
3166 margin *= kVeneerNoProtectionFactor;
3167 }
3168 if (force_emit || ShouldEmitVeneers(margin)) {
3169 EmitVeneers(force_emit, require_jump, margin);
3170 } else {
3171 next_veneer_pool_check_ =
3172 unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
3173 }
3174 }
3175
3176
buffer_space() const3177 int Assembler::buffer_space() const {
3178 return static_cast<int>(reloc_info_writer.pos() -
3179 reinterpret_cast<byte*>(pc_));
3180 }
3181
3182
RecordConstPool(int size)3183 void Assembler::RecordConstPool(int size) {
3184 // We only need this for debugger support, to correctly compute offsets in the
3185 // code.
3186 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3187 }
3188
3189
PatchAdrFar(int64_t target_offset)3190 void PatchingAssembler::PatchAdrFar(int64_t target_offset) {
3191 // The code at the current instruction should be:
3192 // adr rd, 0
3193 // nop (adr_far)
3194 // nop (adr_far)
3195 // movz scratch, 0
3196
3197 // Verify the expected code.
3198 Instruction* expected_adr = InstructionAt(0);
3199 CHECK(expected_adr->IsAdr() && (expected_adr->ImmPCRel() == 0));
3200 int rd_code = expected_adr->Rd();
3201 for (int i = 0; i < kAdrFarPatchableNNops; ++i) {
3202 CHECK(InstructionAt((i + 1) * kInstructionSize)->IsNop(ADR_FAR_NOP));
3203 }
3204 Instruction* expected_movz =
3205 InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize);
3206 CHECK(expected_movz->IsMovz() &&
3207 (expected_movz->ImmMoveWide() == 0) &&
3208 (expected_movz->ShiftMoveWide() == 0));
3209 int scratch_code = expected_movz->Rd();
3210
3211 // Patch to load the correct address.
3212 Register rd = Register::XRegFromCode(rd_code);
3213 Register scratch = Register::XRegFromCode(scratch_code);
3214 // Addresses are only 48 bits.
3215 adr(rd, target_offset & 0xFFFF);
3216 movz(scratch, (target_offset >> 16) & 0xFFFF, 16);
3217 movk(scratch, (target_offset >> 32) & 0xFFFF, 32);
3218 DCHECK((target_offset >> 48) == 0);
3219 add(rd, rd, scratch);
3220 }
3221
3222
3223 } // namespace internal
3224 } // namespace v8
3225
3226 #endif // V8_TARGET_ARCH_ARM64
3227