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