Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1140)

Side by Side Diff: src/a64/assembler-a64.cc

Issue 144963003: A64: add missing files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/a64/assembler-a64.h ('k') | src/a64/assembler-a64-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "v8.h"
30
31 #if defined(V8_TARGET_ARCH_A64)
32
33 #include "a64/assembler-a64-inl.h"
34
35 namespace v8 {
36 namespace internal {
37
38
39 // -----------------------------------------------------------------------------
40 // CpuFeatures utilities (for V8 compatibility).
41
42 ExternalReference ExternalReference::cpu_features() {
43 return ExternalReference(&CpuFeatures::supported_);
44 }
45
46
47 // -----------------------------------------------------------------------------
48 // CPURegList utilities.
49
50 CPURegister CPURegList::PopLowestIndex() {
51 ASSERT(IsValid());
52 if (IsEmpty()) {
53 return NoCPUReg;
54 }
55 int index = CountTrailingZeros(list_, kRegListSizeInBits);
56 ASSERT((1 << index) & list_);
57 Remove(index);
58 return CPURegister(index, size_, type_);
59 }
60
61
62 CPURegister CPURegList::PopHighestIndex() {
63 ASSERT(IsValid());
64 if (IsEmpty()) {
65 return NoCPUReg;
66 }
67 int index = CountLeadingZeros(list_, kRegListSizeInBits);
68 index = kRegListSizeInBits - 1 - index;
69 ASSERT((1 << index) & list_);
70 Remove(index);
71 return CPURegister(index, size_, type_);
72 }
73
74
75 void CPURegList::RemoveCalleeSaved() {
76 if (type() == CPURegister::kRegister) {
77 Remove(GetCalleeSaved(RegisterSizeInBits()));
78 } else if (type() == CPURegister::kFPRegister) {
79 Remove(GetCalleeSavedFP(RegisterSizeInBits()));
80 } else {
81 ASSERT(type() == CPURegister::kNoRegister);
82 ASSERT(IsEmpty());
83 // The list must already be empty, so do nothing.
84 }
85 }
86
87
88 CPURegList CPURegList::GetCalleeSaved(unsigned size) {
89 return CPURegList(CPURegister::kRegister, size, 19, 29);
90 }
91
92
93 CPURegList CPURegList::GetCalleeSavedFP(unsigned size) {
94 return CPURegList(CPURegister::kFPRegister, size, 8, 15);
95 }
96
97
98 CPURegList CPURegList::GetCallerSaved(unsigned size) {
99 // Registers x0-x18 and lr (x30) are caller-saved.
100 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18);
101 list.Combine(lr);
102 return list;
103 }
104
105
106 CPURegList CPURegList::GetCallerSavedFP(unsigned size) {
107 // Registers d0-d7 and d16-d31 are caller-saved.
108 CPURegList list = CPURegList(CPURegister::kFPRegister, size, 0, 7);
109 list.Combine(CPURegList(CPURegister::kFPRegister, size, 16, 31));
110 return list;
111 }
112
113
114 const CPURegList kCalleeSaved = CPURegList::GetCalleeSaved();
115 const CPURegList kCalleeSavedFP = CPURegList::GetCalleeSavedFP();
116 const CPURegList kCallerSaved = CPURegList::GetCallerSaved();
117 const CPURegList kCallerSavedFP = CPURegList::GetCallerSavedFP();
118
119
120 // This function defines the list of registers which are associated with a
121 // safepoint slot. Safepoint register slots are saved contiguously on the stack.
122 // MacroAssembler::SafepointRegisterStackIndex handles mapping from register
123 // code to index in the safepoint register slots. Any change here can affect
124 // this mapping.
125 CPURegList CPURegList::GetSafepointSavedRegisters() {
126 CPURegList list = CPURegList::GetCalleeSaved();
127 list.Combine(CPURegList(CPURegister::kRegister, kXRegSize, kJSCallerSaved));
128
129 // Note that unfortunately we can't use symbolic names for registers and have
130 // to directly use register codes. This is because this function is used to
131 // initialize some static variables and we can't rely on register variables
132 // to be initialized due to static initialization order issues in C++.
133
134 // Drop ip0 and ip1 (i.e. x16 and x17), as they should not be expected to be
135 // preserved outside of the macro assembler.
136 list.Remove(16);
137 list.Remove(17);
138
139 // Add x18 to the safepoint list, as although it's not in kJSCallerSaved, it
140 // is a caller-saved register according to the procedure call standard.
141 list.Combine(18);
142
143 // Drop jssp as the stack pointer doesn't need to be included.
144 list.Remove(28);
145
146 // Add the link register (x30) to the safepoint list.
147 list.Combine(30);
148
149 return list;
150 }
151
152 // -----------------------------------------------------------------------------
153 // Implementation of RelocInfo
154
155 const int RelocInfo::kApplyMask = 0;
156
157
158 bool RelocInfo::IsCodedSpecially() {
159 // The deserializer needs to know whether a pointer is specially coded. Being
160 // specially coded on A64 means that it is a movz/movk sequence. We don't
161 // generate those for relocatable pointers.
162 return false;
163 }
164
165
166 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
167 // Patch the code at the current address with the supplied instructions.
168 Instr* pc = reinterpret_cast<Instr*>(pc_);
169 Instr* instr = reinterpret_cast<Instr*>(instructions);
170 for (int i = 0; i < instruction_count; i++) {
171 *(pc + i) = *(instr + i);
172 }
173
174 // Indicate that code has changed.
175 CPU::FlushICache(pc_, instruction_count * kInstructionSize);
176 }
177
178
179 // Patch the code at the current PC with a call to the target address.
180 // Additional guard instructions can be added if required.
181 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
182 UNIMPLEMENTED();
183 }
184
185
186 // Registers.
187 #define XREG(n) x##n,
188 const Register Register::xregisters[] = {
189 REGISTER_CODE_LIST(XREG)
190 };
191 #undef XREG
192
193 #define WREG(n) w##n,
194 const Register Register::wregisters[] = {
195 REGISTER_CODE_LIST(WREG)
196 };
197 #undef WREG
198
199 #define SREG(n) s##n,
200 const FPRegister FPRegister::sregisters[] = {
201 REGISTER_CODE_LIST(SREG)
202 };
203 #undef SREG
204
205 #define DREG(n) d##n,
206 const FPRegister FPRegister::dregisters[] = {
207 REGISTER_CODE_LIST(DREG)
208 };
209 #undef DREG
210
211 bool AreAliased(const CPURegister& reg1, const CPURegister& reg2,
212 const CPURegister& reg3, const CPURegister& reg4,
213 const CPURegister& reg5, const CPURegister& reg6,
214 const CPURegister& reg7, const CPURegister& reg8) {
215 int number_of_valid_regs = 0;
216 int number_of_valid_fpregs = 0;
217
218 RegList unique_regs = 0;
219 RegList unique_fpregs = 0;
220
221 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
222
223 for (unsigned i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) {
224 if (regs[i].IsRegister()) {
225 number_of_valid_regs++;
226 unique_regs |= regs[i].Bit();
227 } else if (regs[i].IsFPRegister()) {
228 number_of_valid_fpregs++;
229 unique_fpregs |= regs[i].Bit();
230 } else {
231 ASSERT(!regs[i].IsValid());
232 }
233 }
234
235 int number_of_unique_regs =
236 CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte);
237 int number_of_unique_fpregs =
238 CountSetBits(unique_fpregs, sizeof(unique_fpregs) * kBitsPerByte);
239
240 ASSERT(number_of_valid_regs >= number_of_unique_regs);
241 ASSERT(number_of_valid_fpregs >= number_of_unique_fpregs);
242
243 return (number_of_valid_regs != number_of_unique_regs) ||
244 (number_of_valid_fpregs != number_of_unique_fpregs);
245 }
246
247
248 bool AreSameSizeAndType(const CPURegister& reg1, const CPURegister& reg2,
249 const CPURegister& reg3, const CPURegister& reg4,
250 const CPURegister& reg5, const CPURegister& reg6,
251 const CPURegister& reg7, const CPURegister& reg8) {
252 ASSERT(reg1.IsValid());
253 bool match = true;
254 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
255 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
256 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
257 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
258 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
259 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
260 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
261 return match;
262 }
263
264
265 Operand::Operand(const ExternalReference& f)
266 : immediate_(reinterpret_cast<intptr_t>(f.address())),
267 reg_(NoReg),
268 rmode_(RelocInfo::EXTERNAL_REFERENCE) {}
269
270
271 Operand::Operand(Handle<Object> handle) : reg_(NoReg) {
272 #ifdef DEBUG
273 Isolate* isolate = Isolate::Current();
274 #endif
275 AllowDeferredHandleDereference using_raw_address;
276
277 // Verify all Objects referred by code are NOT in new space.
278 Object* obj = *handle;
279 ASSERT(!isolate->heap()->InNewSpace(obj));
280 if (obj->IsHeapObject()) {
281 immediate_ = reinterpret_cast<intptr_t>(handle.location());
282 rmode_ = RelocInfo::EMBEDDED_OBJECT;
283 } else {
284 STATIC_ASSERT(sizeof(intptr_t) == sizeof(int64_t));
285 immediate_ = reinterpret_cast<intptr_t>(obj);
286 rmode_ = RelocInfo::NONE64;
287 }
288 }
289
290
291 bool Operand::NeedsRelocation() const {
292 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
293 #ifdef DEBUG
294 if (!Serializer::enabled()) {
295 Serializer::TooLateToEnableNow();
296 }
297 #endif
298 return Serializer::enabled();
299 }
300
301 return !RelocInfo::IsNone(rmode_);
302 }
303
304
305 // Assembler
306
307 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
308 : AssemblerBase(isolate, buffer, buffer_size),
309 recorded_ast_id_(TypeFeedbackId::None()),
310 positions_recorder_(this) {
311 const_pool_blocked_nesting_ = 0;
312 Reset();
313 }
314
315
316 Assembler::~Assembler() {
317 ASSERT(finalized_ || (pc_ == buffer_));
318 ASSERT(num_pending_reloc_info_ == 0);
319 ASSERT(const_pool_blocked_nesting_ == 0);
320 }
321
322
323 void Assembler::Reset() {
324 #ifdef DEBUG
325 ASSERT((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_));
326 ASSERT(const_pool_blocked_nesting_ == 0);
327 memset(buffer_, 0, pc_ - buffer_);
328 finalized_ = false;
329 #endif
330 pc_ = buffer_;
331 reloc_info_writer.Reposition(reinterpret_cast<byte*>(buffer_ + buffer_size_),
332 reinterpret_cast<byte*>(pc_));
333 num_pending_reloc_info_ = 0;
334 next_buffer_check_ = 0;
335 no_const_pool_before_ = 0;
336 first_const_pool_use_ = -1;
337 ClearRecordedAstId();
338 }
339
340
341 void Assembler::GetCode(CodeDesc* desc) {
342 // Emit constant pool if necessary.
343 CheckConstPool(true, false);
344 ASSERT(num_pending_reloc_info_ == 0);
345
346 // Set up code descriptor.
347 if (desc) {
348 desc->buffer = reinterpret_cast<byte*>(buffer_);
349 desc->buffer_size = buffer_size_;
350 desc->instr_size = pc_offset();
351 desc->reloc_size = (reinterpret_cast<byte*>(buffer_) + buffer_size_) -
352 reloc_info_writer.pos();
353 }
354
355 #ifdef DEBUG
356 finalized_ = true;
357 #endif
358 }
359
360
361 void Assembler::Align(int m) {
362 ASSERT(m >= 4 && IsPowerOf2(m));
363 while ((pc_offset() & (m - 1)) != 0) {
364 nop();
365 }
366 }
367
368
369 inline void Assembler::CheckLabelLinkChain(Label const * label) {
370 #ifdef DEBUG
371 if (label->is_linked()) {
372 int linkoffset = label->pos();
373 bool start_of_chain = false;
374 while (!start_of_chain) {
375 Instruction * link = InstructionAt(linkoffset);
376 int linkpcoffset = link->ImmPCOffset();
377 int prevlinkoffset = linkoffset + linkpcoffset;
378
379 start_of_chain = (linkoffset == prevlinkoffset);
380 linkoffset = linkoffset + linkpcoffset;
381 }
382 }
383 #endif
384 }
385
386
387 void Assembler::bind(Label* label) {
388 // Bind label to the address at pc_. All instructions (most likely branches)
389 // that are linked to this label will be updated to point to the newly-bound
390 // label.
391
392 ASSERT(!label->is_near_linked());
393 ASSERT(!label->is_bound());
394
395 // If the label is linked, the link chain looks something like this:
396 //
397 // |--I----I-------I-------L
398 // |---------------------->| pc_offset
399 // |-------------->| linkoffset = label->pos()
400 // |<------| link->ImmPCOffset()
401 // |------>| prevlinkoffset = linkoffset + link->ImmPCOffset()
402 //
403 // On each iteration, the last link is updated and then removed from the
404 // chain until only one remains. At that point, the label is bound.
405 //
406 // If the label is not linked, no preparation is required before binding.
407 while (label->is_linked()) {
408 int linkoffset = label->pos();
409 Instruction* link = InstructionAt(linkoffset);
410 int prevlinkoffset = linkoffset + link->ImmPCOffset();
411
412 CheckLabelLinkChain(label);
413
414 ASSERT(linkoffset >= 0);
415 ASSERT(linkoffset < pc_offset());
416 ASSERT((linkoffset > prevlinkoffset) ||
417 (linkoffset - prevlinkoffset == kStartOfLabelLinkChain));
418 ASSERT(prevlinkoffset >= 0);
419
420 // Update the link to point to the label.
421 link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
422
423 // Link the label to the previous link in the chain.
424 if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) {
425 // We hit kStartOfLabelLinkChain, so the chain is fully processed.
426 label->Unuse();
427 } else {
428 // Update the label for the next iteration.
429 label->link_to(prevlinkoffset);
430 }
431 }
432 label->bind_to(pc_offset());
433
434 ASSERT(label->is_bound());
435 ASSERT(!label->is_linked());
436 }
437
438
439 int Assembler::LinkAndGetByteOffsetTo(Label* label) {
440 ASSERT(sizeof(*pc_) == 1);
441 CheckLabelLinkChain(label);
442
443 int offset;
444 if (label->is_bound()) {
445 // The label is bound, so it does not need to be updated. Referring
446 // instructions must link directly to the label as they will not be
447 // updated.
448 //
449 // In this case, label->pos() returns the offset of the label from the
450 // start of the buffer.
451 //
452 // Note that offset can be zero for self-referential instructions. (This
453 // could be useful for ADR, for example.)
454 offset = label->pos() - pc_offset();
455 ASSERT(offset <= 0);
456 } else {
457 if (label->is_linked()) {
458 // The label is linked, so the referring instruction should be added onto
459 // the end of the label's link chain.
460 //
461 // In this case, label->pos() returns the offset of the last linked
462 // instruction from the start of the buffer.
463 offset = label->pos() - pc_offset();
464 ASSERT(offset != kStartOfLabelLinkChain);
465 // Note that the offset here needs to be PC-relative only so that the
466 // first instruction in a buffer can link to an unbound label. Otherwise,
467 // the offset would be 0 for this case, and 0 is reserved for
468 // kStartOfLabelLinkChain.
469 } else {
470 // The label is unused, so it now becomes linked and the referring
471 // instruction is at the start of the new link chain.
472 offset = kStartOfLabelLinkChain;
473 }
474 // The instruction at pc is now the last link in the label's chain.
475 label->link_to(pc_offset());
476 }
477
478 return offset;
479 }
480
481
482 void Assembler::StartBlockConstPool() {
483 if (const_pool_blocked_nesting_++ == 0) {
484 // Prevent constant pool checks happening by setting the next check to
485 // the biggest possible offset.
486 next_buffer_check_ = kMaxInt;
487 }
488 }
489
490
491 void Assembler::EndBlockConstPool() {
492 if (--const_pool_blocked_nesting_ == 0) {
493 // Check the constant pool hasn't been blocked for too long.
494 ASSERT((num_pending_reloc_info_ == 0) ||
495 (pc_offset() < (first_const_pool_use_ + kMaxDistToPool)));
496 // Two cases:
497 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
498 // still blocked
499 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
500 // trigger a check.
501 next_buffer_check_ = no_const_pool_before_;
502 }
503 }
504
505
506 bool Assembler::is_const_pool_blocked() const {
507 return (const_pool_blocked_nesting_ > 0) ||
508 (pc_offset() < no_const_pool_before_);
509 }
510
511
512 bool Assembler::IsConstantPoolAt(Instruction* instr) {
513 // The constant pool marker is made of two instructions. These instructions
514 // will never be emitted by the JIT, so checking for the first one is enough:
515 // 0: ldr xzr, #<size of pool>
516 bool result = instr->IsLdrLiteralX() && (instr->Rt() == xzr.code());
517
518 // It is still worth asserting the marker is complete.
519 // 4: blr xzr
520 ASSERT(!result || (instr->following()->IsBranchAndLinkToRegister() &&
521 instr->following()->Rn() == xzr.code()));
522
523 return result;
524 }
525
526
527 int Assembler::ConstantPoolSizeAt(Instruction* instr) {
528 if (IsConstantPoolAt(instr)) {
529 return instr->ImmLLiteral();
530 } else {
531 return -1;
532 }
533 }
534
535
536 void Assembler::ConstantPoolMarker(uint32_t size) {
537 ASSERT(is_const_pool_blocked());
538 // + 1 is for the crash guard.
539 Emit(LDR_x_lit | ImmLLiteral(2 * size + 1) | Rt(xzr));
540 }
541
542
543 void Assembler::ConstantPoolGuard() {
544 #ifdef DEBUG
545 // Currently this is only used after a constant pool marker.
546 ASSERT(is_const_pool_blocked());
547 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
548 ASSERT(instr->preceding()->IsLdrLiteralX() &&
549 instr->preceding()->Rt() == xzr.code());
550 #endif
551
552 // Crash by branching to 0. lr now points near the fault.
553 // TODO(all): update the simulator to trap this pattern.
554 Emit(BLR | Rn(xzr));
555 }
556
557
558 void Assembler::br(const Register& xn) {
559 positions_recorder()->WriteRecordedPositions();
560 ASSERT(xn.Is64Bits());
561 Emit(BR | Rn(xn));
562 }
563
564
565 void Assembler::blr(const Register& xn) {
566 positions_recorder()->WriteRecordedPositions();
567 ASSERT(xn.Is64Bits());
568 // The pattern 'blr xzr' is used as a guard to detect when execution falls
569 // through the constant pool. It should not be emitted.
570 ASSERT(!xn.Is(xzr));
571 Emit(BLR | Rn(xn));
572 }
573
574
575 void Assembler::ret(const Register& xn) {
576 positions_recorder()->WriteRecordedPositions();
577 ASSERT(xn.Is64Bits());
578 Emit(RET | Rn(xn));
579 }
580
581
582 void Assembler::b(int imm26) {
583 Emit(B | ImmUncondBranch(imm26));
584 }
585
586
587 void Assembler::b(Label* label) {
588 positions_recorder()->WriteRecordedPositions();
589 b(LinkAndGetInstructionOffsetTo(label));
590 }
591
592
593 void Assembler::b(int imm19, Condition cond) {
594 Emit(B_cond | ImmCondBranch(imm19) | cond);
595 }
596
597
598 void Assembler::b(Label* label, Condition cond) {
599 positions_recorder()->WriteRecordedPositions();
600 b(LinkAndGetInstructionOffsetTo(label), cond);
601 }
602
603
604 void Assembler::bl(int imm26) {
605 positions_recorder()->WriteRecordedPositions();
606 Emit(BL | ImmUncondBranch(imm26));
607 }
608
609
610 void Assembler::bl(Label* label) {
611 positions_recorder()->WriteRecordedPositions();
612 bl(LinkAndGetInstructionOffsetTo(label));
613 }
614
615
616 void Assembler::cbz(const Register& rt,
617 int imm19) {
618 positions_recorder()->WriteRecordedPositions();
619 Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));
620 }
621
622
623 void Assembler::cbz(const Register& rt,
624 Label* label) {
625 positions_recorder()->WriteRecordedPositions();
626 cbz(rt, LinkAndGetInstructionOffsetTo(label));
627 }
628
629
630 void Assembler::cbnz(const Register& rt,
631 int imm19) {
632 positions_recorder()->WriteRecordedPositions();
633 Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));
634 }
635
636
637 void Assembler::cbnz(const Register& rt,
638 Label* label) {
639 positions_recorder()->WriteRecordedPositions();
640 cbnz(rt, LinkAndGetInstructionOffsetTo(label));
641 }
642
643
644 void Assembler::tbz(const Register& rt,
645 unsigned bit_pos,
646 int imm14) {
647 positions_recorder()->WriteRecordedPositions();
648 ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));
649 Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
650 }
651
652
653 void Assembler::tbz(const Register& rt,
654 unsigned bit_pos,
655 Label* label) {
656 positions_recorder()->WriteRecordedPositions();
657 tbz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
658 }
659
660
661 void Assembler::tbnz(const Register& rt,
662 unsigned bit_pos,
663 int imm14) {
664 positions_recorder()->WriteRecordedPositions();
665 ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));
666 Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
667 }
668
669
670 void Assembler::tbnz(const Register& rt,
671 unsigned bit_pos,
672 Label* label) {
673 positions_recorder()->WriteRecordedPositions();
674 tbnz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
675 }
676
677
678 void Assembler::adr(const Register& rd, int imm21) {
679 ASSERT(rd.Is64Bits());
680 Emit(ADR | ImmPCRelAddress(imm21) | Rd(rd));
681 }
682
683
684 void Assembler::adr(const Register& rd, Label* label) {
685 adr(rd, LinkAndGetByteOffsetTo(label));
686 }
687
688
689 void Assembler::add(const Register& rd,
690 const Register& rn,
691 const Operand& operand) {
692 AddSub(rd, rn, operand, LeaveFlags, ADD);
693 }
694
695
696 void Assembler::adds(const Register& rd,
697 const Register& rn,
698 const Operand& operand) {
699 AddSub(rd, rn, operand, SetFlags, ADD);
700 }
701
702
703 void Assembler::cmn(const Register& rn,
704 const Operand& operand) {
705 Register zr = AppropriateZeroRegFor(rn);
706 adds(zr, rn, operand);
707 }
708
709
710 void Assembler::sub(const Register& rd,
711 const Register& rn,
712 const Operand& operand) {
713 AddSub(rd, rn, operand, LeaveFlags, SUB);
714 }
715
716
717 void Assembler::subs(const Register& rd,
718 const Register& rn,
719 const Operand& operand) {
720 AddSub(rd, rn, operand, SetFlags, SUB);
721 }
722
723
724 void Assembler::cmp(const Register& rn, const Operand& operand) {
725 Register zr = AppropriateZeroRegFor(rn);
726 subs(zr, rn, operand);
727 }
728
729
730 void Assembler::neg(const Register& rd, const Operand& operand) {
731 Register zr = AppropriateZeroRegFor(rd);
732 sub(rd, zr, operand);
733 }
734
735
736 void Assembler::negs(const Register& rd, const Operand& operand) {
737 Register zr = AppropriateZeroRegFor(rd);
738 subs(rd, zr, operand);
739 }
740
741
742 void Assembler::adc(const Register& rd,
743 const Register& rn,
744 const Operand& operand) {
745 AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);
746 }
747
748
749 void Assembler::adcs(const Register& rd,
750 const Register& rn,
751 const Operand& operand) {
752 AddSubWithCarry(rd, rn, operand, SetFlags, ADC);
753 }
754
755
756 void Assembler::sbc(const Register& rd,
757 const Register& rn,
758 const Operand& operand) {
759 AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);
760 }
761
762
763 void Assembler::sbcs(const Register& rd,
764 const Register& rn,
765 const Operand& operand) {
766 AddSubWithCarry(rd, rn, operand, SetFlags, SBC);
767 }
768
769
770 void Assembler::ngc(const Register& rd, const Operand& operand) {
771 Register zr = AppropriateZeroRegFor(rd);
772 sbc(rd, zr, operand);
773 }
774
775
776 void Assembler::ngcs(const Register& rd, const Operand& operand) {
777 Register zr = AppropriateZeroRegFor(rd);
778 sbcs(rd, zr, operand);
779 }
780
781
782 // Logical instructions.
783 void Assembler::and_(const Register& rd,
784 const Register& rn,
785 const Operand& operand) {
786 Logical(rd, rn, operand, AND);
787 }
788
789
790 void Assembler::ands(const Register& rd,
791 const Register& rn,
792 const Operand& operand) {
793 Logical(rd, rn, operand, ANDS);
794 }
795
796
797 void Assembler::tst(const Register& rn,
798 const Operand& operand) {
799 ands(AppropriateZeroRegFor(rn), rn, operand);
800 }
801
802
803 void Assembler::bic(const Register& rd,
804 const Register& rn,
805 const Operand& operand) {
806 Logical(rd, rn, operand, BIC);
807 }
808
809
810 void Assembler::bics(const Register& rd,
811 const Register& rn,
812 const Operand& operand) {
813 Logical(rd, rn, operand, BICS);
814 }
815
816
817 void Assembler::orr(const Register& rd,
818 const Register& rn,
819 const Operand& operand) {
820 Logical(rd, rn, operand, ORR);
821 }
822
823
824 void Assembler::orn(const Register& rd,
825 const Register& rn,
826 const Operand& operand) {
827 Logical(rd, rn, operand, ORN);
828 }
829
830
831 void Assembler::eor(const Register& rd,
832 const Register& rn,
833 const Operand& operand) {
834 Logical(rd, rn, operand, EOR);
835 }
836
837
838 void Assembler::eon(const Register& rd,
839 const Register& rn,
840 const Operand& operand) {
841 Logical(rd, rn, operand, EON);
842 }
843
844
845 void Assembler::lslv(const Register& rd,
846 const Register& rn,
847 const Register& rm) {
848 ASSERT(rd.SizeInBits() == rn.SizeInBits());
849 ASSERT(rd.SizeInBits() == rm.SizeInBits());
850 Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));
851 }
852
853
854 void Assembler::lsrv(const Register& rd,
855 const Register& rn,
856 const Register& rm) {
857 ASSERT(rd.SizeInBits() == rn.SizeInBits());
858 ASSERT(rd.SizeInBits() == rm.SizeInBits());
859 Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));
860 }
861
862
863 void Assembler::asrv(const Register& rd,
864 const Register& rn,
865 const Register& rm) {
866 ASSERT(rd.SizeInBits() == rn.SizeInBits());
867 ASSERT(rd.SizeInBits() == rm.SizeInBits());
868 Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));
869 }
870
871
872 void Assembler::rorv(const Register& rd,
873 const Register& rn,
874 const Register& rm) {
875 ASSERT(rd.SizeInBits() == rn.SizeInBits());
876 ASSERT(rd.SizeInBits() == rm.SizeInBits());
877 Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));
878 }
879
880
881 // Bitfield operations.
882 void Assembler::bfm(const Register& rd,
883 const Register& rn,
884 unsigned immr,
885 unsigned imms) {
886 ASSERT(rd.SizeInBits() == rn.SizeInBits());
887 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
888 Emit(SF(rd) | BFM | N |
889 ImmR(immr, rd.SizeInBits()) |
890 ImmS(imms, rn.SizeInBits()) |
891 Rn(rn) | Rd(rd));
892 }
893
894
895 void Assembler::sbfm(const Register& rd,
896 const Register& rn,
897 unsigned immr,
898 unsigned imms) {
899 ASSERT(rd.Is64Bits() || rn.Is32Bits());
900 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
901 Emit(SF(rd) | SBFM | N |
902 ImmR(immr, rd.SizeInBits()) |
903 ImmS(imms, rn.SizeInBits()) |
904 Rn(rn) | Rd(rd));
905 }
906
907
908 void Assembler::ubfm(const Register& rd,
909 const Register& rn,
910 unsigned immr,
911 unsigned imms) {
912 ASSERT(rd.SizeInBits() == rn.SizeInBits());
913 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
914 Emit(SF(rd) | UBFM | N |
915 ImmR(immr, rd.SizeInBits()) |
916 ImmS(imms, rn.SizeInBits()) |
917 Rn(rn) | Rd(rd));
918 }
919
920
921 void Assembler::extr(const Register& rd,
922 const Register& rn,
923 const Register& rm,
924 unsigned lsb) {
925 ASSERT(rd.SizeInBits() == rn.SizeInBits());
926 ASSERT(rd.SizeInBits() == rm.SizeInBits());
927 Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
928 Emit(SF(rd) | EXTR | N | Rm(rm) |
929 ImmS(lsb, rn.SizeInBits()) | Rn(rn) | Rd(rd));
930 }
931
932
933 void Assembler::csel(const Register& rd,
934 const Register& rn,
935 const Register& rm,
936 Condition cond) {
937 ConditionalSelect(rd, rn, rm, cond, CSEL);
938 }
939
940
941 void Assembler::csinc(const Register& rd,
942 const Register& rn,
943 const Register& rm,
944 Condition cond) {
945 ConditionalSelect(rd, rn, rm, cond, CSINC);
946 }
947
948
949 void Assembler::csinv(const Register& rd,
950 const Register& rn,
951 const Register& rm,
952 Condition cond) {
953 ConditionalSelect(rd, rn, rm, cond, CSINV);
954 }
955
956
957 void Assembler::csneg(const Register& rd,
958 const Register& rn,
959 const Register& rm,
960 Condition cond) {
961 ConditionalSelect(rd, rn, rm, cond, CSNEG);
962 }
963
964
965 void Assembler::cset(const Register &rd, Condition cond) {
966 ASSERT((cond != al) && (cond != nv));
967 Register zr = AppropriateZeroRegFor(rd);
968 csinc(rd, zr, zr, InvertCondition(cond));
969 }
970
971
972 void Assembler::csetm(const Register &rd, Condition cond) {
973 ASSERT((cond != al) && (cond != nv));
974 Register zr = AppropriateZeroRegFor(rd);
975 csinv(rd, zr, zr, InvertCondition(cond));
976 }
977
978
979 void Assembler::cinc(const Register &rd, const Register &rn, Condition cond) {
980 ASSERT((cond != al) && (cond != nv));
981 csinc(rd, rn, rn, InvertCondition(cond));
982 }
983
984
985 void Assembler::cinv(const Register &rd, const Register &rn, Condition cond) {
986 ASSERT((cond != al) && (cond != nv));
987 csinv(rd, rn, rn, InvertCondition(cond));
988 }
989
990
991 void Assembler::cneg(const Register &rd, const Register &rn, Condition cond) {
992 ASSERT((cond != al) && (cond != nv));
993 csneg(rd, rn, rn, InvertCondition(cond));
994 }
995
996
997 void Assembler::ConditionalSelect(const Register& rd,
998 const Register& rn,
999 const Register& rm,
1000 Condition cond,
1001 ConditionalSelectOp op) {
1002 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1003 ASSERT(rd.SizeInBits() == rm.SizeInBits());
1004 Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));
1005 }
1006
1007
1008 void Assembler::ccmn(const Register& rn,
1009 const Operand& operand,
1010 StatusFlags nzcv,
1011 Condition cond) {
1012 ConditionalCompare(rn, operand, nzcv, cond, CCMN);
1013 }
1014
1015
1016 void Assembler::ccmp(const Register& rn,
1017 const Operand& operand,
1018 StatusFlags nzcv,
1019 Condition cond) {
1020 ConditionalCompare(rn, operand, nzcv, cond, CCMP);
1021 }
1022
1023
1024 void Assembler::DataProcessing3Source(const Register& rd,
1025 const Register& rn,
1026 const Register& rm,
1027 const Register& ra,
1028 DataProcessing3SourceOp op) {
1029 Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));
1030 }
1031
1032
1033 void Assembler::mul(const Register& rd,
1034 const Register& rn,
1035 const Register& rm) {
1036 ASSERT(AreSameSizeAndType(rd, rn, rm));
1037 Register zr = AppropriateZeroRegFor(rn);
1038 DataProcessing3Source(rd, rn, rm, zr, MADD);
1039 }
1040
1041
1042 void Assembler::madd(const Register& rd,
1043 const Register& rn,
1044 const Register& rm,
1045 const Register& ra) {
1046 ASSERT(AreSameSizeAndType(rd, rn, rm, ra));
1047 DataProcessing3Source(rd, rn, rm, ra, MADD);
1048 }
1049
1050
1051 void Assembler::mneg(const Register& rd,
1052 const Register& rn,
1053 const Register& rm) {
1054 ASSERT(AreSameSizeAndType(rd, rn, rm));
1055 Register zr = AppropriateZeroRegFor(rn);
1056 DataProcessing3Source(rd, rn, rm, zr, MSUB);
1057 }
1058
1059
1060 void Assembler::msub(const Register& rd,
1061 const Register& rn,
1062 const Register& rm,
1063 const Register& ra) {
1064 ASSERT(AreSameSizeAndType(rd, rn, rm, ra));
1065 DataProcessing3Source(rd, rn, rm, ra, MSUB);
1066 }
1067
1068
1069 void Assembler::smaddl(const Register& rd,
1070 const Register& rn,
1071 const Register& rm,
1072 const Register& ra) {
1073 ASSERT(rd.Is64Bits() && ra.Is64Bits());
1074 ASSERT(rn.Is32Bits() && rm.Is32Bits());
1075 DataProcessing3Source(rd, rn, rm, ra, SMADDL_x);
1076 }
1077
1078
1079 void Assembler::smsubl(const Register& rd,
1080 const Register& rn,
1081 const Register& rm,
1082 const Register& ra) {
1083 ASSERT(rd.Is64Bits() && ra.Is64Bits());
1084 ASSERT(rn.Is32Bits() && rm.Is32Bits());
1085 DataProcessing3Source(rd, rn, rm, ra, SMSUBL_x);
1086 }
1087
1088
1089 void Assembler::umaddl(const Register& rd,
1090 const Register& rn,
1091 const Register& rm,
1092 const Register& ra) {
1093 ASSERT(rd.Is64Bits() && ra.Is64Bits());
1094 ASSERT(rn.Is32Bits() && rm.Is32Bits());
1095 DataProcessing3Source(rd, rn, rm, ra, UMADDL_x);
1096 }
1097
1098
1099 void Assembler::umsubl(const Register& rd,
1100 const Register& rn,
1101 const Register& rm,
1102 const Register& ra) {
1103 ASSERT(rd.Is64Bits() && ra.Is64Bits());
1104 ASSERT(rn.Is32Bits() && rm.Is32Bits());
1105 DataProcessing3Source(rd, rn, rm, ra, UMSUBL_x);
1106 }
1107
1108
1109 void Assembler::smull(const Register& rd,
1110 const Register& rn,
1111 const Register& rm) {
1112 ASSERT(rd.Is64Bits());
1113 ASSERT(rn.Is32Bits() && rm.Is32Bits());
1114 DataProcessing3Source(rd, rn, rm, xzr, SMADDL_x);
1115 }
1116
1117
1118 void Assembler::smulh(const Register& rd,
1119 const Register& rn,
1120 const Register& rm) {
1121 ASSERT(AreSameSizeAndType(rd, rn, rm));
1122 DataProcessing3Source(rd, rn, rm, xzr, SMULH_x);
1123 }
1124
1125
1126 void Assembler::sdiv(const Register& rd,
1127 const Register& rn,
1128 const Register& rm) {
1129 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1130 ASSERT(rd.SizeInBits() == rm.SizeInBits());
1131 Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));
1132 }
1133
1134
1135 void Assembler::udiv(const Register& rd,
1136 const Register& rn,
1137 const Register& rm) {
1138 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1139 ASSERT(rd.SizeInBits() == rm.SizeInBits());
1140 Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));
1141 }
1142
1143
1144 void Assembler::rbit(const Register& rd,
1145 const Register& rn) {
1146 DataProcessing1Source(rd, rn, RBIT);
1147 }
1148
1149
1150 void Assembler::rev16(const Register& rd,
1151 const Register& rn) {
1152 DataProcessing1Source(rd, rn, REV16);
1153 }
1154
1155
1156 void Assembler::rev32(const Register& rd,
1157 const Register& rn) {
1158 ASSERT(rd.Is64Bits());
1159 DataProcessing1Source(rd, rn, REV);
1160 }
1161
1162
1163 void Assembler::rev(const Register& rd,
1164 const Register& rn) {
1165 DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);
1166 }
1167
1168
1169 void Assembler::clz(const Register& rd,
1170 const Register& rn) {
1171 DataProcessing1Source(rd, rn, CLZ);
1172 }
1173
1174
1175 void Assembler::cls(const Register& rd,
1176 const Register& rn) {
1177 DataProcessing1Source(rd, rn, CLS);
1178 }
1179
1180
1181 void Assembler::ldp(const CPURegister& rt,
1182 const CPURegister& rt2,
1183 const MemOperand& src) {
1184 LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
1185 }
1186
1187
1188 void Assembler::stp(const CPURegister& rt,
1189 const CPURegister& rt2,
1190 const MemOperand& dst) {
1191 LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
1192 }
1193
1194
1195 void Assembler::ldpsw(const Register& rt,
1196 const Register& rt2,
1197 const MemOperand& src) {
1198 ASSERT(rt.Is64Bits());
1199 LoadStorePair(rt, rt2, src, LDPSW_x);
1200 }
1201
1202
1203 void Assembler::LoadStorePair(const CPURegister& rt,
1204 const CPURegister& rt2,
1205 const MemOperand& addr,
1206 LoadStorePairOp op) {
1207 // 'rt' and 'rt2' can only be aliased for stores.
1208 ASSERT(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));
1209 ASSERT(AreSameSizeAndType(rt, rt2));
1210
1211 Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
1212 ImmLSPair(addr.offset(), CalcLSPairDataSize(op));
1213
1214 Instr addrmodeop;
1215 if (addr.IsImmediateOffset()) {
1216 addrmodeop = LoadStorePairOffsetFixed;
1217 } else {
1218 // Pre-index and post-index modes.
1219 ASSERT(!rt.Is(addr.base()));
1220 ASSERT(!rt2.Is(addr.base()));
1221 ASSERT(addr.offset() != 0);
1222 if (addr.IsPreIndex()) {
1223 addrmodeop = LoadStorePairPreIndexFixed;
1224 } else {
1225 ASSERT(addr.IsPostIndex());
1226 addrmodeop = LoadStorePairPostIndexFixed;
1227 }
1228 }
1229 Emit(addrmodeop | memop);
1230 }
1231
1232
1233 void Assembler::ldnp(const CPURegister& rt,
1234 const CPURegister& rt2,
1235 const MemOperand& src) {
1236 LoadStorePairNonTemporal(rt, rt2, src,
1237 LoadPairNonTemporalOpFor(rt, rt2));
1238 }
1239
1240
1241 void Assembler::stnp(const CPURegister& rt,
1242 const CPURegister& rt2,
1243 const MemOperand& dst) {
1244 LoadStorePairNonTemporal(rt, rt2, dst,
1245 StorePairNonTemporalOpFor(rt, rt2));
1246 }
1247
1248
1249 void Assembler::LoadStorePairNonTemporal(const CPURegister& rt,
1250 const CPURegister& rt2,
1251 const MemOperand& addr,
1252 LoadStorePairNonTemporalOp op) {
1253 ASSERT(!rt.Is(rt2));
1254 ASSERT(AreSameSizeAndType(rt, rt2));
1255 ASSERT(addr.IsImmediateOffset());
1256
1257 LSDataSize size = CalcLSPairDataSize(
1258 static_cast<LoadStorePairOp>(op & LoadStorePairMask));
1259 Emit(op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
1260 ImmLSPair(addr.offset(), size));
1261 }
1262
1263
1264 // Memory instructions.
1265 void Assembler::ldrb(const Register& rt, const MemOperand& src) {
1266 LoadStore(rt, src, LDRB_w);
1267 }
1268
1269
1270 void Assembler::strb(const Register& rt, const MemOperand& dst) {
1271 LoadStore(rt, dst, STRB_w);
1272 }
1273
1274
1275 void Assembler::ldrsb(const Register& rt, const MemOperand& src) {
1276 LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w);
1277 }
1278
1279
1280 void Assembler::ldrh(const Register& rt, const MemOperand& src) {
1281 LoadStore(rt, src, LDRH_w);
1282 }
1283
1284
1285 void Assembler::strh(const Register& rt, const MemOperand& dst) {
1286 LoadStore(rt, dst, STRH_w);
1287 }
1288
1289
1290 void Assembler::ldrsh(const Register& rt, const MemOperand& src) {
1291 LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w);
1292 }
1293
1294
1295 void Assembler::ldr(const CPURegister& rt, const MemOperand& src) {
1296 LoadStore(rt, src, LoadOpFor(rt));
1297 }
1298
1299
1300 void Assembler::str(const CPURegister& rt, const MemOperand& src) {
1301 LoadStore(rt, src, StoreOpFor(rt));
1302 }
1303
1304
1305 void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
1306 ASSERT(rt.Is64Bits());
1307 LoadStore(rt, src, LDRSW_x);
1308 }
1309
1310
1311 void Assembler::ldr(const Register& rt, uint64_t imm) {
1312 // TODO(all): Constant pool may be garbage collected. Hence we cannot store
1313 // TODO(all): arbitrary values in them. Manually move it for now.
1314 // TODO(all): Fix MacroAssembler::Fmov when this is implemented.
1315 UNIMPLEMENTED();
1316 }
1317
1318
1319 void Assembler::ldr(const FPRegister& ft, double imm) {
1320 // TODO(all): Constant pool may be garbage collected. Hence we cannot store
1321 // TODO(all): arbitrary values in them. Manually move it for now.
1322 // TODO(all): Fix MacroAssembler::Fmov when this is implemented.
1323 UNIMPLEMENTED();
1324 }
1325
1326
1327 void Assembler::mov(const Register& rd, const Register& rm) {
1328 // Moves involving the stack pointer are encoded as add immediate with
1329 // second operand of zero. Otherwise, orr with first operand zr is
1330 // used.
1331 if (rd.IsSP() || rm.IsSP()) {
1332 add(rd, rm, 0);
1333 } else {
1334 orr(rd, AppropriateZeroRegFor(rd), rm);
1335 }
1336 }
1337
1338 void Assembler::mvn(const Register& rd, const Operand& operand) {
1339 orn(rd, AppropriateZeroRegFor(rd), operand);
1340 }
1341
1342
1343 void Assembler::mrs(const Register& rt, SystemRegister sysreg) {
1344 ASSERT(rt.Is64Bits());
1345 Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt));
1346 }
1347
1348
1349 void Assembler::msr(SystemRegister sysreg, const Register& rt) {
1350 ASSERT(rt.Is64Bits());
1351 Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg));
1352 }
1353
1354
1355 void Assembler::hint(SystemHint code) {
1356 Emit(HINT | ImmHint(code) | Rt(xzr));
1357 }
1358
1359 void Assembler::dmb(BarrierDomain domain, BarrierType type) {
1360 Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));
1361 }
1362
1363 void Assembler::dsb(BarrierDomain domain, BarrierType type) {
1364 Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));
1365 }
1366
1367 void Assembler::isb() {
1368 Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));
1369 }
1370
1371 void Assembler::fmov(FPRegister fd, double imm) {
1372 if (fd.Is64Bits() && IsImmFP64(imm)) {
1373 Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm));
1374 } else if (fd.Is32Bits() && IsImmFP32(imm)) {
1375 Emit(FMOV_s_imm | Rd(fd) | ImmFP32(static_cast<float>(imm)));
1376 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
1377 Register zr = AppropriateZeroRegFor(fd);
1378 fmov(fd, zr);
1379 } else {
1380 ldr(fd, imm);
1381 }
1382 }
1383
1384
1385 void Assembler::fmov(Register rd, FPRegister fn) {
1386 ASSERT(rd.SizeInBits() == fn.SizeInBits());
1387 FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd;
1388 Emit(op | Rd(rd) | Rn(fn));
1389 }
1390
1391
1392 void Assembler::fmov(FPRegister fd, Register rn) {
1393 ASSERT(fd.SizeInBits() == rn.SizeInBits());
1394 FPIntegerConvertOp op = fd.Is32Bits() ? FMOV_sw : FMOV_dx;
1395 Emit(op | Rd(fd) | Rn(rn));
1396 }
1397
1398
1399 void Assembler::fmov(FPRegister fd, FPRegister fn) {
1400 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1401 Emit(FPType(fd) | FMOV | Rd(fd) | Rn(fn));
1402 }
1403
1404
1405 void Assembler::fadd(const FPRegister& fd,
1406 const FPRegister& fn,
1407 const FPRegister& fm) {
1408 FPDataProcessing2Source(fd, fn, fm, FADD);
1409 }
1410
1411
1412 void Assembler::fsub(const FPRegister& fd,
1413 const FPRegister& fn,
1414 const FPRegister& fm) {
1415 FPDataProcessing2Source(fd, fn, fm, FSUB);
1416 }
1417
1418
1419 void Assembler::fmul(const FPRegister& fd,
1420 const FPRegister& fn,
1421 const FPRegister& fm) {
1422 FPDataProcessing2Source(fd, fn, fm, FMUL);
1423 }
1424
1425
1426 void Assembler::fmadd(const FPRegister& fd,
1427 const FPRegister& fn,
1428 const FPRegister& fm,
1429 const FPRegister& fa) {
1430 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d);
1431 }
1432
1433
1434 void Assembler::fmsub(const FPRegister& fd,
1435 const FPRegister& fn,
1436 const FPRegister& fm,
1437 const FPRegister& fa) {
1438 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d);
1439 }
1440
1441
1442 void Assembler::fnmadd(const FPRegister& fd,
1443 const FPRegister& fn,
1444 const FPRegister& fm,
1445 const FPRegister& fa) {
1446 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d);
1447 }
1448
1449
1450 void Assembler::fnmsub(const FPRegister& fd,
1451 const FPRegister& fn,
1452 const FPRegister& fm,
1453 const FPRegister& fa) {
1454 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d);
1455 }
1456
1457
1458 void Assembler::fdiv(const FPRegister& fd,
1459 const FPRegister& fn,
1460 const FPRegister& fm) {
1461 FPDataProcessing2Source(fd, fn, fm, FDIV);
1462 }
1463
1464
1465 void Assembler::fmax(const FPRegister& fd,
1466 const FPRegister& fn,
1467 const FPRegister& fm) {
1468 FPDataProcessing2Source(fd, fn, fm, FMAX);
1469 }
1470
1471
1472 void Assembler::fmaxnm(const FPRegister& fd,
1473 const FPRegister& fn,
1474 const FPRegister& fm) {
1475 FPDataProcessing2Source(fd, fn, fm, FMAXNM);
1476 }
1477
1478
1479 void Assembler::fmin(const FPRegister& fd,
1480 const FPRegister& fn,
1481 const FPRegister& fm) {
1482 FPDataProcessing2Source(fd, fn, fm, FMIN);
1483 }
1484
1485
1486 void Assembler::fminnm(const FPRegister& fd,
1487 const FPRegister& fn,
1488 const FPRegister& fm) {
1489 FPDataProcessing2Source(fd, fn, fm, FMINNM);
1490 }
1491
1492
1493 void Assembler::fabs(const FPRegister& fd,
1494 const FPRegister& fn) {
1495 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1496 FPDataProcessing1Source(fd, fn, FABS);
1497 }
1498
1499
1500 void Assembler::fneg(const FPRegister& fd,
1501 const FPRegister& fn) {
1502 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1503 FPDataProcessing1Source(fd, fn, FNEG);
1504 }
1505
1506
1507 void Assembler::fsqrt(const FPRegister& fd,
1508 const FPRegister& fn) {
1509 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1510 FPDataProcessing1Source(fd, fn, FSQRT);
1511 }
1512
1513
1514 void Assembler::frinta(const FPRegister& fd,
1515 const FPRegister& fn) {
1516 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1517 FPDataProcessing1Source(fd, fn, FRINTA);
1518 }
1519
1520
1521 void Assembler::frintn(const FPRegister& fd,
1522 const FPRegister& fn) {
1523 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1524 FPDataProcessing1Source(fd, fn, FRINTN);
1525 }
1526
1527
1528 void Assembler::frintz(const FPRegister& fd,
1529 const FPRegister& fn) {
1530 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1531 FPDataProcessing1Source(fd, fn, FRINTZ);
1532 }
1533
1534
1535 void Assembler::fcmp(const FPRegister& fn,
1536 const FPRegister& fm) {
1537 ASSERT(fn.SizeInBits() == fm.SizeInBits());
1538 Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn));
1539 }
1540
1541
1542 void Assembler::fcmp(const FPRegister& fn,
1543 double value) {
1544 USE(value);
1545 // Although the fcmp instruction can strictly only take an immediate value of
1546 // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't
1547 // affect the result of the comparison.
1548 ASSERT(value == 0.0);
1549 Emit(FPType(fn) | FCMP_zero | Rn(fn));
1550 }
1551
1552
1553 void Assembler::fccmp(const FPRegister& fn,
1554 const FPRegister& fm,
1555 StatusFlags nzcv,
1556 Condition cond) {
1557 ASSERT(fn.SizeInBits() == fm.SizeInBits());
1558 Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv));
1559 }
1560
1561
1562 void Assembler::fcsel(const FPRegister& fd,
1563 const FPRegister& fn,
1564 const FPRegister& fm,
1565 Condition cond) {
1566 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1567 ASSERT(fd.SizeInBits() == fm.SizeInBits());
1568 Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd));
1569 }
1570
1571
1572 void Assembler::FPConvertToInt(const Register& rd,
1573 const FPRegister& fn,
1574 FPIntegerConvertOp op) {
1575 Emit(SF(rd) | FPType(fn) | op | Rn(fn) | Rd(rd));
1576 }
1577
1578
1579 void Assembler::fcvt(const FPRegister& fd,
1580 const FPRegister& fn) {
1581 if (fd.Is64Bits()) {
1582 // Convert float to double.
1583 ASSERT(fn.Is32Bits());
1584 FPDataProcessing1Source(fd, fn, FCVT_ds);
1585 } else {
1586 // Convert double to float.
1587 ASSERT(fn.Is64Bits());
1588 FPDataProcessing1Source(fd, fn, FCVT_sd);
1589 }
1590 }
1591
1592
1593 void Assembler::fcvtau(const Register& rd, const FPRegister& fn) {
1594 FPConvertToInt(rd, fn, FCVTAU);
1595 }
1596
1597
1598 void Assembler::fcvtas(const Register& rd, const FPRegister& fn) {
1599 FPConvertToInt(rd, fn, FCVTAS);
1600 }
1601
1602
1603 void Assembler::fcvtmu(const Register& rd, const FPRegister& fn) {
1604 FPConvertToInt(rd, fn, FCVTMU);
1605 }
1606
1607
1608 void Assembler::fcvtms(const Register& rd, const FPRegister& fn) {
1609 FPConvertToInt(rd, fn, FCVTMS);
1610 }
1611
1612
1613 void Assembler::fcvtnu(const Register& rd, const FPRegister& fn) {
1614 FPConvertToInt(rd, fn, FCVTNU);
1615 }
1616
1617
1618 void Assembler::fcvtns(const Register& rd, const FPRegister& fn) {
1619 FPConvertToInt(rd, fn, FCVTNS);
1620 }
1621
1622
1623 void Assembler::fcvtzu(const Register& rd, const FPRegister& fn) {
1624 FPConvertToInt(rd, fn, FCVTZU);
1625 }
1626
1627
1628 void Assembler::fcvtzs(const Register& rd, const FPRegister& fn) {
1629 FPConvertToInt(rd, fn, FCVTZS);
1630 }
1631
1632
1633 void Assembler::scvtf(const FPRegister& fd,
1634 const Register& rn,
1635 unsigned fbits) {
1636 if (fbits == 0) {
1637 Emit(SF(rn) | FPType(fd) | SCVTF | Rn(rn) | Rd(fd));
1638 } else {
1639 Emit(SF(rn) | FPType(fd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
1640 Rd(fd));
1641 }
1642 }
1643
1644
1645 void Assembler::ucvtf(const FPRegister& fd,
1646 const Register& rn,
1647 unsigned fbits) {
1648 if (fbits == 0) {
1649 Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd));
1650 } else {
1651 Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
1652 Rd(fd));
1653 }
1654 }
1655
1656
1657 // Note:
1658 // Below, a difference in case for the same letter indicates a
1659 // negated bit.
1660 // If b is 1, then B is 0.
1661 Instr Assembler::ImmFP32(float imm) {
1662 ASSERT(IsImmFP32(imm));
1663 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
1664 uint32_t bits = float_to_rawbits(imm);
1665 // bit7: a000.0000
1666 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
1667 // bit6: 0b00.0000
1668 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
1669 // bit5_to_0: 00cd.efgh
1670 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
1671
1672 return (bit7 | bit6 | bit5_to_0) << ImmFP_offset;
1673 }
1674
1675
1676 Instr Assembler::ImmFP64(double imm) {
1677 ASSERT(IsImmFP64(imm));
1678 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
1679 // 0000.0000.0000.0000.0000.0000.0000.0000
1680 uint64_t bits = double_to_rawbits(imm);
1681 // bit7: a000.0000
1682 uint32_t bit7 = ((bits >> 63) & 0x1) << 7;
1683 // bit6: 0b00.0000
1684 uint32_t bit6 = ((bits >> 61) & 0x1) << 6;
1685 // bit5_to_0: 00cd.efgh
1686 uint32_t bit5_to_0 = (bits >> 48) & 0x3f;
1687
1688 return (bit7 | bit6 | bit5_to_0) << ImmFP_offset;
1689 }
1690
1691
1692 // Code generation helpers.
1693 void Assembler::MoveWide(const Register& rd,
1694 uint64_t imm,
1695 int shift,
1696 MoveWideImmediateOp mov_op) {
1697 if (shift >= 0) {
1698 // Explicit shift specified.
1699 ASSERT((shift == 0) || (shift == 16) || (shift == 32) || (shift == 48));
1700 ASSERT(rd.Is64Bits() || (shift == 0) || (shift == 16));
1701 shift /= 16;
1702 } else {
1703 // Calculate a new immediate and shift combination to encode the immediate
1704 // argument.
1705 shift = 0;
1706 if ((imm & ~0xffffUL) == 0) {
1707 // Nothing to do.
1708 } else if ((imm & ~(0xffffUL << 16)) == 0) {
1709 imm >>= 16;
1710 shift = 1;
1711 } else if ((imm & ~(0xffffUL << 32)) == 0) {
1712 ASSERT(rd.Is64Bits());
1713 imm >>= 32;
1714 shift = 2;
1715 } else if ((imm & ~(0xffffUL << 48)) == 0) {
1716 ASSERT(rd.Is64Bits());
1717 imm >>= 48;
1718 shift = 3;
1719 }
1720 }
1721
1722 ASSERT(is_uint16(imm));
1723
1724 Emit(SF(rd) | MoveWideImmediateFixed | mov_op |
1725 Rd(rd) | ImmMoveWide(imm) | ShiftMoveWide(shift));
1726 }
1727
1728
1729 void Assembler::AddSub(const Register& rd,
1730 const Register& rn,
1731 const Operand& operand,
1732 FlagsUpdate S,
1733 AddSubOp op) {
1734 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1735 ASSERT(!operand.NeedsRelocation());
1736 if (operand.IsImmediate()) {
1737 int64_t immediate = operand.immediate();
1738 ASSERT(IsImmAddSub(immediate));
1739 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
1740 Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |
1741 ImmAddSub(immediate) | dest_reg | RnSP(rn));
1742 } else if (operand.IsShiftedRegister()) {
1743 ASSERT(operand.reg().SizeInBits() == rd.SizeInBits());
1744 ASSERT(operand.shift() != ROR);
1745
1746 // For instructions of the form:
1747 // add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ]
1748 // add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ]
1749 // add/sub wsp, wsp, <Wm> [, LSL #0-3 ]
1750 // adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]
1751 // or their 64-bit register equivalents, convert the operand from shifted to
1752 // extended register mode, and emit an add/sub extended instruction.
1753 if (rn.IsSP() || rd.IsSP()) {
1754 ASSERT(!(rd.IsSP() && (S == SetFlags)));
1755 DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S,
1756 AddSubExtendedFixed | op);
1757 } else {
1758 DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op);
1759 }
1760 } else {
1761 ASSERT(operand.IsExtendedRegister());
1762 DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op);
1763 }
1764 }
1765
1766
1767 void Assembler::AddSubWithCarry(const Register& rd,
1768 const Register& rn,
1769 const Operand& operand,
1770 FlagsUpdate S,
1771 AddSubWithCarryOp op) {
1772 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1773 ASSERT(rd.SizeInBits() == operand.reg().SizeInBits());
1774 ASSERT(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
1775 ASSERT(!operand.NeedsRelocation());
1776 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd));
1777 }
1778
1779
1780 void Assembler::hlt(int code) {
1781 ASSERT(is_uint16(code));
1782 Emit(HLT | ImmException(code));
1783 }
1784
1785
1786 void Assembler::brk(int code) {
1787 ASSERT(is_uint16(code));
1788 Emit(BRK | ImmException(code));
1789 }
1790
1791
1792 void Assembler::debug(const char* message, uint32_t code, Instr params) {
1793 #ifdef USE_SIMULATOR
1794 // The arguments to the debug marker need to be contiguous in memory, so make
1795 // sure we don't try to emit a literal pool.
1796 BlockConstPoolScope scope(this);
1797
1798 Label start;
1799 bind(&start);
1800
1801 // Refer to instructions-a64.h for a description of the marker and its
1802 // arguments.
1803 hlt(kImmExceptionIsDebug);
1804 ASSERT(SizeOfCodeGeneratedSince(&start) == kDebugCodeOffset);
1805 dc32(code);
1806 ASSERT(SizeOfCodeGeneratedSince(&start) == kDebugParamsOffset);
1807 dc32(params);
1808 ASSERT(SizeOfCodeGeneratedSince(&start) == kDebugMessageOffset);
1809 EmitStringData(message);
1810 hlt(kImmExceptionIsUnreachable);
1811 #endif
1812 }
1813
1814
1815 void Assembler::Logical(const Register& rd,
1816 const Register& rn,
1817 const Operand& operand,
1818 LogicalOp op) {
1819 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1820 ASSERT(!operand.NeedsRelocation());
1821 if (operand.IsImmediate()) {
1822 int64_t immediate = operand.immediate();
1823 unsigned reg_size = rd.SizeInBits();
1824
1825 ASSERT(immediate != 0);
1826 ASSERT(immediate != -1);
1827 ASSERT(rd.Is64Bits() || is_uint32(immediate));
1828
1829 // If the operation is NOT, invert the operation and immediate.
1830 if ((op & NOT) == NOT) {
1831 op = static_cast<LogicalOp>(op & ~NOT);
1832 immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);
1833 }
1834
1835 unsigned n, imm_s, imm_r;
1836 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
1837 // Immediate can be encoded in the instruction.
1838 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
1839 } else {
1840 // This case is handled in the macro assembler.
1841 UNREACHABLE();
1842 }
1843 } else {
1844 ASSERT(operand.IsShiftedRegister());
1845 ASSERT(operand.reg().SizeInBits() == rd.SizeInBits());
1846 Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed);
1847 DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);
1848 }
1849 }
1850
1851
1852 void Assembler::LogicalImmediate(const Register& rd,
1853 const Register& rn,
1854 unsigned n,
1855 unsigned imm_s,
1856 unsigned imm_r,
1857 LogicalOp op) {
1858 unsigned reg_size = rd.SizeInBits();
1859 Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);
1860 Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |
1861 ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |
1862 Rn(rn));
1863 }
1864
1865
1866 void Assembler::ConditionalCompare(const Register& rn,
1867 const Operand& operand,
1868 StatusFlags nzcv,
1869 Condition cond,
1870 ConditionalCompareOp op) {
1871 Instr ccmpop;
1872 ASSERT(!operand.NeedsRelocation());
1873 if (operand.IsImmediate()) {
1874 int64_t immediate = operand.immediate();
1875 ASSERT(IsImmConditionalCompare(immediate));
1876 ccmpop = ConditionalCompareImmediateFixed | op | ImmCondCmp(immediate);
1877 } else {
1878 ASSERT(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
1879 ccmpop = ConditionalCompareRegisterFixed | op | Rm(operand.reg());
1880 }
1881 Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));
1882 }
1883
1884
1885 void Assembler::DataProcessing1Source(const Register& rd,
1886 const Register& rn,
1887 DataProcessing1SourceOp op) {
1888 ASSERT(rd.SizeInBits() == rn.SizeInBits());
1889 Emit(SF(rn) | op | Rn(rn) | Rd(rd));
1890 }
1891
1892
1893 void Assembler::FPDataProcessing1Source(const FPRegister& fd,
1894 const FPRegister& fn,
1895 FPDataProcessing1SourceOp op) {
1896 Emit(FPType(fn) | op | Rn(fn) | Rd(fd));
1897 }
1898
1899
1900 void Assembler::FPDataProcessing2Source(const FPRegister& fd,
1901 const FPRegister& fn,
1902 const FPRegister& fm,
1903 FPDataProcessing2SourceOp op) {
1904 ASSERT(fd.SizeInBits() == fn.SizeInBits());
1905 ASSERT(fd.SizeInBits() == fm.SizeInBits());
1906 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd));
1907 }
1908
1909
1910 void Assembler::FPDataProcessing3Source(const FPRegister& fd,
1911 const FPRegister& fn,
1912 const FPRegister& fm,
1913 const FPRegister& fa,
1914 FPDataProcessing3SourceOp op) {
1915 ASSERT(AreSameSizeAndType(fd, fn, fm, fa));
1916 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa));
1917 }
1918
1919
1920 void Assembler::EmitShift(const Register& rd,
1921 const Register& rn,
1922 Shift shift,
1923 unsigned shift_amount) {
1924 switch (shift) {
1925 case LSL:
1926 lsl(rd, rn, shift_amount);
1927 break;
1928 case LSR:
1929 lsr(rd, rn, shift_amount);
1930 break;
1931 case ASR:
1932 asr(rd, rn, shift_amount);
1933 break;
1934 case ROR:
1935 ror(rd, rn, shift_amount);
1936 break;
1937 default:
1938 UNREACHABLE();
1939 }
1940 }
1941
1942
1943 void Assembler::EmitExtendShift(const Register& rd,
1944 const Register& rn,
1945 Extend extend,
1946 unsigned left_shift) {
1947 ASSERT(rd.SizeInBits() >= rn.SizeInBits());
1948 unsigned reg_size = rd.SizeInBits();
1949 // Use the correct size of register.
1950 Register rn_ = Register(rn.code(), rd.SizeInBits());
1951 // Bits extracted are high_bit:0.
1952 unsigned high_bit = (8 << (extend & 0x3)) - 1;
1953 // Number of bits left in the result that are not introduced by the shift.
1954 unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);
1955
1956 if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {
1957 switch (extend) {
1958 case UXTB:
1959 case UXTH:
1960 case UXTW: ubfm(rd, rn_, non_shift_bits, high_bit); break;
1961 case SXTB:
1962 case SXTH:
1963 case SXTW: sbfm(rd, rn_, non_shift_bits, high_bit); break;
1964 case UXTX:
1965 case SXTX: {
1966 ASSERT(rn.SizeInBits() == kXRegSize);
1967 // Nothing to extend. Just shift.
1968 lsl(rd, rn_, left_shift);
1969 break;
1970 }
1971 default: UNREACHABLE();
1972 }
1973 } else {
1974 // No need to extend as the extended bits would be shifted away.
1975 lsl(rd, rn_, left_shift);
1976 }
1977 }
1978
1979
1980 void Assembler::DataProcShiftedRegister(const Register& rd,
1981 const Register& rn,
1982 const Operand& operand,
1983 FlagsUpdate S,
1984 Instr op) {
1985 ASSERT(operand.IsShiftedRegister());
1986 ASSERT(rn.Is64Bits() || (rn.Is32Bits() && is_uint5(operand.shift_amount())));
1987 ASSERT(!operand.NeedsRelocation());
1988 Emit(SF(rd) | op | Flags(S) |
1989 ShiftDP(operand.shift()) | ImmDPShift(operand.shift_amount()) |
1990 Rm(operand.reg()) | Rn(rn) | Rd(rd));
1991 }
1992
1993
1994 void Assembler::DataProcExtendedRegister(const Register& rd,
1995 const Register& rn,
1996 const Operand& operand,
1997 FlagsUpdate S,
1998 Instr op) {
1999 ASSERT(!operand.NeedsRelocation());
2000 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
2001 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) |
2002 ExtendMode(operand.extend()) | ImmExtendShift(operand.shift_amount()) |
2003 dest_reg | RnSP(rn));
2004 }
2005
2006
2007 bool Assembler::IsImmAddSub(int64_t immediate) {
2008 return is_uint12(immediate) ||
2009 (is_uint12(immediate >> 12) && ((immediate & 0xfff) == 0));
2010 }
2011
2012 void Assembler::LoadStore(const CPURegister& rt,
2013 const MemOperand& addr,
2014 LoadStoreOp op) {
2015 Instr memop = op | Rt(rt) | RnSP(addr.base());
2016 ptrdiff_t offset = addr.offset();
2017
2018 if (addr.IsImmediateOffset()) {
2019 LSDataSize size = CalcLSDataSize(op);
2020 if (IsImmLSScaled(offset, size)) {
2021 // Use the scaled addressing mode.
2022 Emit(LoadStoreUnsignedOffsetFixed | memop |
2023 ImmLSUnsigned(offset >> size));
2024 } else if (IsImmLSUnscaled(offset)) {
2025 // Use the unscaled addressing mode.
2026 Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset));
2027 } else {
2028 // This case is handled in the macro assembler.
2029 UNREACHABLE();
2030 }
2031 } else if (addr.IsRegisterOffset()) {
2032 Extend ext = addr.extend();
2033 Shift shift = addr.shift();
2034 unsigned shift_amount = addr.shift_amount();
2035
2036 // LSL is encoded in the option field as UXTX.
2037 if (shift == LSL) {
2038 ext = UXTX;
2039 }
2040
2041 // Shifts are encoded in one bit, indicating a left shift by the memory
2042 // access size.
2043 ASSERT((shift_amount == 0) ||
2044 (shift_amount == static_cast<unsigned>(CalcLSDataSize(op))));
2045 Emit(LoadStoreRegisterOffsetFixed | memop | Rm(addr.regoffset()) |
2046 ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0));
2047 } else {
2048 // Pre-index and post-index modes.
2049 ASSERT(!rt.Is(addr.base()));
2050 if (IsImmLSUnscaled(offset)) {
2051 if (addr.IsPreIndex()) {
2052 Emit(LoadStorePreIndexFixed | memop | ImmLS(offset));
2053 } else {
2054 ASSERT(addr.IsPostIndex());
2055 Emit(LoadStorePostIndexFixed | memop | ImmLS(offset));
2056 }
2057 } else {
2058 // This case is handled in the macro assembler.
2059 UNREACHABLE();
2060 }
2061 }
2062 }
2063
2064
2065 bool Assembler::IsImmLSUnscaled(ptrdiff_t offset) {
2066 return is_int9(offset);
2067 }
2068
2069
2070 bool Assembler::IsImmLSScaled(ptrdiff_t offset, LSDataSize size) {
2071 bool offset_is_size_multiple = (((offset >> size) << size) == offset);
2072 return offset_is_size_multiple && is_uint12(offset >> size);
2073 }
2074
2075
2076 void Assembler::LoadLiteral(const CPURegister& rt, int offset_from_pc) {
2077 ASSERT((offset_from_pc & ((1 << kLiteralEntrySizeLog2) - 1)) == 0);
2078 // The pattern 'ldr xzr, #offset' is used to indicate the beginning of a
2079 // constant pool. It should not be emitted.
2080 ASSERT(!rt.Is(xzr));
2081 Emit(LDR_x_lit |
2082 ImmLLiteral(offset_from_pc >> kLiteralEntrySizeLog2) |
2083 Rt(rt));
2084 }
2085
2086
2087 void Assembler::LoadRelocatedValue(const CPURegister& rt,
2088 const Operand& operand,
2089 LoadLiteralOp op) {
2090 int64_t imm = operand.immediate();
2091 ASSERT(is_int32(imm) || is_uint32(imm) || (rt.Is64Bits()));
2092 RecordRelocInfo(operand.rmode(), imm);
2093 BlockConstPoolFor(1);
2094 Emit(op | ImmLLiteral(0) | Rt(rt));
2095 }
2096
2097
2098 // Test if a given value can be encoded in the immediate field of a logical
2099 // instruction.
2100 // If it can be encoded, the function returns true, and values pointed to by n,
2101 // imm_s and imm_r are updated with immediates encoded in the format required
2102 // by the corresponding fields in the logical instruction.
2103 // If it can not be encoded, the function returns false, and the values pointed
2104 // to by n, imm_s and imm_r are undefined.
2105 bool Assembler::IsImmLogical(uint64_t value,
2106 unsigned width,
2107 unsigned* n,
2108 unsigned* imm_s,
2109 unsigned* imm_r) {
2110 ASSERT((n != NULL) && (imm_s != NULL) && (imm_r != NULL));
2111 ASSERT((width == kWRegSize) || (width == kXRegSize));
2112
2113 // Logical immediates are encoded using parameters n, imm_s and imm_r using
2114 // the following table:
2115 //
2116 // N imms immr size S R
2117 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
2118 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
2119 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
2120 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
2121 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
2122 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
2123 // (s bits must not be all set)
2124 //
2125 // A pattern is constructed of size bits, where the least significant S+1
2126 // bits are set. The pattern is rotated right by R, and repeated across a
2127 // 32 or 64-bit value, depending on destination register width.
2128 //
2129 // To test if an arbitary immediate can be encoded using this scheme, an
2130 // iterative algorithm is used.
2131 //
2132 // TODO(mcapewel) This code does not consider using X/W register overlap to
2133 // support 64-bit immediates where the top 32-bits are zero, and the bottom
2134 // 32-bits are an encodable logical immediate.
2135
2136 // 1. If the value has all set or all clear bits, it can't be encoded.
2137 if ((value == 0) || (value == 0xffffffffffffffffUL) ||
2138 ((width == kWRegSize) && (value == 0xffffffff))) {
2139 return false;
2140 }
2141
2142 unsigned lead_zero = CountLeadingZeros(value, width);
2143 unsigned lead_one = CountLeadingZeros(~value, width);
2144 unsigned trail_zero = CountTrailingZeros(value, width);
2145 unsigned trail_one = CountTrailingZeros(~value, width);
2146 unsigned set_bits = CountSetBits(value, width);
2147
2148 // The fixed bits in the immediate s field.
2149 // If width == 64 (X reg), start at 0xFFFFFF80.
2150 // If width == 32 (W reg), start at 0xFFFFFFC0, as the iteration for 64-bit
2151 // widths won't be executed.
2152 int imm_s_fixed = (width == kXRegSize) ? -128 : -64;
2153 int imm_s_mask = 0x3F;
2154
2155 for (;;) {
2156 // 2. If the value is two bits wide, it can be encoded.
2157 if (width == 2) {
2158 *n = 0;
2159 *imm_s = 0x3C;
2160 *imm_r = (value & 3) - 1;
2161 return true;
2162 }
2163
2164 *n = (width == 64) ? 1 : 0;
2165 *imm_s = ((imm_s_fixed | (set_bits - 1)) & imm_s_mask);
2166 if ((lead_zero + set_bits) == width) {
2167 *imm_r = 0;
2168 } else {
2169 *imm_r = (lead_zero > 0) ? (width - trail_zero) : lead_one;
2170 }
2171
2172 // 3. If the sum of leading zeros, trailing zeros and set bits is equal to
2173 // the bit width of the value, it can be encoded.
2174 if (lead_zero + trail_zero + set_bits == width) {
2175 return true;
2176 }
2177
2178 // 4. If the sum of leading ones, trailing ones and unset bits in the
2179 // value is equal to the bit width of the value, it can be encoded.
2180 if (lead_one + trail_one + (width - set_bits) == width) {
2181 return true;
2182 }
2183
2184 // 5. If the most-significant half of the bitwise value is equal to the
2185 // least-significant half, return to step 2 using the least-significant
2186 // half of the value.
2187 uint64_t mask = (1UL << (width >> 1)) - 1;
2188 if ((value & mask) == ((value >> (width >> 1)) & mask)) {
2189 width >>= 1;
2190 set_bits >>= 1;
2191 imm_s_fixed >>= 1;
2192 continue;
2193 }
2194
2195 // 6. Otherwise, the value can't be encoded.
2196 return false;
2197 }
2198 }
2199
2200 bool Assembler::IsImmConditionalCompare(int64_t immediate) {
2201 return is_uint5(immediate);
2202 }
2203
2204
2205 bool Assembler::IsImmFP32(float imm) {
2206 // Valid values will have the form:
2207 // aBbb.bbbc.defg.h000.0000.0000.0000.0000
2208 uint32_t bits = float_to_rawbits(imm);
2209 // bits[19..0] are cleared.
2210 if ((bits & 0x7ffff) != 0) {
2211 return false;
2212 }
2213
2214 // bits[29..25] are all set or all cleared.
2215 uint32_t b_pattern = (bits >> 16) & 0x3e00;
2216 if (b_pattern != 0 && b_pattern != 0x3e00) {
2217 return false;
2218 }
2219
2220 // bit[30] and bit[29] are opposite.
2221 if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
2222 return false;
2223 }
2224
2225 return true;
2226 }
2227
2228
2229 bool Assembler::IsImmFP64(double imm) {
2230 // Valid values will have the form:
2231 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
2232 // 0000.0000.0000.0000.0000.0000.0000.0000
2233 uint64_t bits = double_to_rawbits(imm);
2234 // bits[47..0] are cleared.
2235 if ((bits & 0xffffffffffffL) != 0) {
2236 return false;
2237 }
2238
2239 // bits[61..54] are all set or all cleared.
2240 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
2241 if (b_pattern != 0 && b_pattern != 0x3fc0) {
2242 return false;
2243 }
2244
2245 // bit[62] and bit[61] are opposite.
2246 if (((bits ^ (bits << 1)) & 0x4000000000000000L) == 0) {
2247 return false;
2248 }
2249
2250 return true;
2251 }
2252
2253
2254 void Assembler::GrowBuffer() {
2255 if (!own_buffer_) FATAL("external code buffer is too small");
2256
2257 // Compute new buffer size.
2258 CodeDesc desc; // the new buffer
2259 if (buffer_size_ < 4 * KB) {
2260 desc.buffer_size = 4 * KB;
2261 } else if (buffer_size_ < 1 * MB) {
2262 desc.buffer_size = 2 * buffer_size_;
2263 } else {
2264 desc.buffer_size = buffer_size_ + 1 * MB;
2265 }
2266 CHECK_GT(desc.buffer_size, 0); // No overflow.
2267
2268 byte* buffer = reinterpret_cast<byte*>(buffer_);
2269
2270 // Set up new buffer.
2271 desc.buffer = NewArray<byte>(desc.buffer_size);
2272
2273 desc.instr_size = pc_offset();
2274 desc.reloc_size = (buffer + buffer_size_) - reloc_info_writer.pos();
2275
2276 // Copy the data.
2277 intptr_t pc_delta = desc.buffer - buffer;
2278 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
2279 (buffer + buffer_size_);
2280 memmove(desc.buffer, buffer, desc.instr_size);
2281 memmove(reloc_info_writer.pos() + rc_delta,
2282 reloc_info_writer.pos(), desc.reloc_size);
2283
2284 // Switch buffers.
2285 DeleteArray(buffer_);
2286 buffer_ = desc.buffer;
2287 buffer_size_ = desc.buffer_size;
2288 pc_ = reinterpret_cast<byte*>(pc_) + pc_delta;
2289 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2290 reloc_info_writer.last_pc() + pc_delta);
2291
2292 // None of our relocation types are pc relative pointing outside the code
2293 // buffer nor pc absolute pointing inside the code buffer, so there is no need
2294 // to relocate any emitted relocation entries.
2295
2296 // Relocate pending relocation entries.
2297 for (int i = 0; i < num_pending_reloc_info_; i++) {
2298 RelocInfo& rinfo = pending_reloc_info_[i];
2299 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2300 rinfo.rmode() != RelocInfo::POSITION);
2301 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2302 rinfo.set_pc(rinfo.pc() + pc_delta);
2303 }
2304 }
2305 }
2306
2307
2308 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, int64_t data) {
2309 // We do not try to reuse pool constants.
2310 RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL);
2311 if (((rmode >= RelocInfo::JS_RETURN) &&
2312 (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) ||
2313 (rmode == RelocInfo::CONST_POOL)) {
2314 // Adjust code for new modes.
2315 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2316 || RelocInfo::IsJSReturn(rmode)
2317 || RelocInfo::IsComment(rmode)
2318 || RelocInfo::IsPosition(rmode)
2319 || RelocInfo::IsConstPool(rmode));
2320 // These modes do not need an entry in the constant pool.
2321 } else {
2322 ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo);
2323 if (num_pending_reloc_info_ == 0) {
2324 first_const_pool_use_ = pc_offset();
2325 }
2326 pending_reloc_info_[num_pending_reloc_info_++] = rinfo;
2327 // Make sure the constant pool is not emitted in place of the next
2328 // instruction for which we just recorded relocation info.
2329 BlockConstPoolFor(1);
2330 }
2331
2332 if (!RelocInfo::IsNone(rmode)) {
2333 // Don't record external references unless the heap will be serialized.
2334 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2335 #ifdef DEBUG
2336 if (!Serializer::enabled()) {
2337 Serializer::TooLateToEnableNow();
2338 }
2339 #endif
2340 if (!Serializer::enabled() && !emit_debug_code()) {
2341 return;
2342 }
2343 }
2344 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2345 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2346 RelocInfo reloc_info_with_ast_id(
2347 reinterpret_cast<byte*>(pc_), rmode, RecordedAstId().ToInt(), NULL);
2348 ClearRecordedAstId();
2349 reloc_info_writer.Write(&reloc_info_with_ast_id);
2350 } else {
2351 reloc_info_writer.Write(&rinfo);
2352 }
2353 }
2354 }
2355
2356
2357 void Assembler::BlockConstPoolFor(int instructions) {
2358 int pc_limit = pc_offset() + instructions * kInstructionSize;
2359 if (no_const_pool_before_ < pc_limit) {
2360 // If there are some pending entries, the constant pool cannot be blocked
2361 // further than first_const_pool_use_ + kMaxDistToPool
2362 ASSERT((num_pending_reloc_info_ == 0) ||
2363 (pc_limit < (first_const_pool_use_ + kMaxDistToPool)));
2364 no_const_pool_before_ = pc_limit;
2365 }
2366
2367 if (next_buffer_check_ < no_const_pool_before_) {
2368 next_buffer_check_ = no_const_pool_before_;
2369 }
2370 }
2371
2372
2373 // TODO(all): We are never trying to emit constant pools after unconditional
2374 // branches, because we only call it from Assembler::Emit() (or manually).
2375 // We should try to enable that.
2376 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2377 // Some short sequence of instruction mustn't be broken up by constant pool
2378 // emission, such sequences are protected by calls to BlockConstPoolFor and
2379 // BlockConstPoolScope.
2380 if (is_const_pool_blocked()) {
2381 // Something is wrong if emission is forced and blocked at the same time.
2382 ASSERT(!force_emit);
2383 return;
2384 }
2385
2386 // There is nothing to do if there are no pending constant pool entries.
2387 if (num_pending_reloc_info_ == 0) {
2388 // Calculate the offset of the next check.
2389 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
2390 return;
2391 }
2392
2393 // We emit a constant pool when:
2394 // * requested to do so by parameter force_emit (e.g. after each function).
2395 // * the distance to the first instruction accessing the constant pool is
2396 // kAvgDistToPool or more.
2397 // * no jump is required and the distance to the first instruction accessing
2398 // the constant pool is at least kMaxDistToPool / 2.
2399 ASSERT(first_const_pool_use_ >= 0);
2400 int dist = pc_offset() - first_const_pool_use_;
2401 if (!force_emit && dist < kAvgDistToPool &&
2402 (require_jump || (dist < (kMaxDistToPool / 2)))) {
2403 return;
2404 }
2405
2406 // Check that the code buffer is large enough before emitting the constant
2407 // pool (include the jump over the pool and the constant pool marker and
2408 // the gap to the relocation information).
2409 int jump_instr = require_jump ? kInstructionSize : 0;
2410 int size = jump_instr + kInstructionSize +
2411 num_pending_reloc_info_ * kPointerSize;
2412 int needed_space = size + kGap;
2413 while (buffer_space() <= needed_space) {
2414 GrowBuffer();
2415 }
2416
2417 {
2418 // Block recursive calls to CheckConstPool.
2419 BlockConstPoolScope block_const_pool(this);
2420 RecordComment("[ Constant Pool");
2421 RecordConstPool(size);
2422
2423 // Emit jump over constant pool if necessary.
2424 Label after_pool;
2425 if (require_jump) {
2426 b(&after_pool);
2427 }
2428
2429 // Emit a constant pool header. The header has two goals:
2430 // 1) Encode the size of the constant pool, for use by the disassembler.
2431 // 2) Terminate the program, to try to prevent execution from accidentally
2432 // flowing into the constant pool.
2433 // The header is therefore made of two a64 instructions:
2434 // ldr xzr, #<size of the constant pool in 32-bit words>
2435 // blr xzr
2436 // If executed the code will likely segfault and lr will point to the
2437 // beginning of the constant pool.
2438 // TODO(all): currently each relocated constant is 64 bits, consider adding
2439 // support for 32-bit entries.
2440 ConstantPoolMarker(2 * num_pending_reloc_info_);
2441 ConstantPoolGuard();
2442
2443 // Emit constant pool entries.
2444 for (int i = 0; i < num_pending_reloc_info_; i++) {
2445 RelocInfo& rinfo = pending_reloc_info_[i];
2446 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2447 rinfo.rmode() != RelocInfo::POSITION &&
2448 rinfo.rmode() != RelocInfo::STATEMENT_POSITION &&
2449 rinfo.rmode() != RelocInfo::CONST_POOL);
2450
2451 Instruction* instr = reinterpret_cast<Instruction*>(rinfo.pc());
2452 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
2453 ASSERT(instr->IsLdrLiteral() &&
2454 instr->ImmLLiteral() == 0);
2455
2456 instr->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
2457 dc64(rinfo.data());
2458 }
2459
2460 num_pending_reloc_info_ = 0;
2461 first_const_pool_use_ = -1;
2462
2463 RecordComment("]");
2464
2465 if (after_pool.is_linked()) {
2466 bind(&after_pool);
2467 }
2468 }
2469
2470 // Since a constant pool was just emitted, move the check offset forward by
2471 // the standard interval.
2472 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
2473 }
2474
2475
2476 void Assembler::RecordComment(const char* msg) {
2477 if (FLAG_code_comments) {
2478 CheckBuffer();
2479 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2480 }
2481 }
2482
2483
2484 int Assembler::buffer_space() const {
2485 return reloc_info_writer.pos() - reinterpret_cast<byte*>(pc_);
2486 }
2487
2488
2489 void Assembler::RecordJSReturn() {
2490 positions_recorder()->WriteRecordedPositions();
2491 CheckBuffer();
2492 RecordRelocInfo(RelocInfo::JS_RETURN);
2493 }
2494
2495
2496 void Assembler::RecordDebugBreakSlot() {
2497 positions_recorder()->WriteRecordedPositions();
2498 CheckBuffer();
2499 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2500 }
2501
2502
2503 void Assembler::RecordConstPool(int size) {
2504 // We only need this for debugger support, to correctly compute offsets in the
2505 // code.
2506 #ifdef ENABLE_DEBUGGER_SUPPORT
2507 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
2508 #endif
2509 }
2510
2511
2512 } } // namespace v8::internal
2513
2514 #endif // V8_TARGET_ARCH_A64
OLDNEW
« no previous file with comments | « src/a64/assembler-a64.h ('k') | src/a64/assembler-a64-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698