1 // Copyright 2015, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "vixl/a64/macro-assembler-a64.h"
28 
29 namespace vixl {
30 
31 
Release()32 void Pool::Release() {
33   if (--monitor_ == 0) {
34     // Ensure the pool has not been blocked for too long.
35     VIXL_ASSERT(masm_->CursorOffset() < checkpoint_);
36   }
37 }
38 
39 
SetNextCheckpoint(ptrdiff_t checkpoint)40 void Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {
41   masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);
42   checkpoint_ = checkpoint;
43 }
44 
45 
LiteralPool(MacroAssembler * masm)46 LiteralPool::LiteralPool(MacroAssembler* masm)
47     : Pool(masm), size_(0), first_use_(-1),
48       recommended_checkpoint_(kNoCheckpointRequired) {
49 }
50 
51 
~LiteralPool()52 LiteralPool::~LiteralPool() {
53   VIXL_ASSERT(IsEmpty());
54   VIXL_ASSERT(!IsBlocked());
55 }
56 
57 
Reset()58 void LiteralPool::Reset() {
59   std::vector<RawLiteral*>::iterator it, end;
60   for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
61     delete *it;
62   }
63   entries_.clear();
64   size_ = 0;
65   first_use_ = -1;
66   Pool::Reset();
67   recommended_checkpoint_ = kNoCheckpointRequired;
68 }
69 
70 
CheckEmitFor(size_t amount,EmitOption option)71 void LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {
72   if (IsEmpty() || IsBlocked()) return;
73 
74   ptrdiff_t distance = masm_->CursorOffset() + amount - first_use_;
75   if (distance >= kRecommendedLiteralPoolRange) {
76     Emit(option);
77   }
78 }
79 
80 
Emit(EmitOption option)81 void LiteralPool::Emit(EmitOption option) {
82   // There is an issue if we are asked to emit a blocked or empty pool.
83   VIXL_ASSERT(!IsBlocked());
84   VIXL_ASSERT(!IsEmpty());
85 
86   size_t pool_size = Size();
87   size_t emit_size = pool_size;
88   if (option == kBranchRequired) emit_size += kInstructionSize;
89   Label end_of_pool;
90 
91   VIXL_ASSERT(emit_size % kInstructionSize == 0);
92   InstructionAccurateScope guard(masm_, emit_size / kInstructionSize);
93   if (option == kBranchRequired) masm_->b(&end_of_pool);
94 
95   // Marker indicating the size of the literal pool in 32-bit words.
96   VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);
97   masm_->ldr(xzr, pool_size / kWRegSizeInBytes);
98 
99   // Now populate the literal pool.
100   std::vector<RawLiteral*>::iterator it, end;
101   for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
102     VIXL_ASSERT((*it)->IsUsed());
103     masm_->place(*it);
104     delete *it;
105   }
106 
107   if (option == kBranchRequired) masm_->bind(&end_of_pool);
108 
109   entries_.clear();
110   Reset();
111 }
112 
113 
AddEntry(RawLiteral * literal)114 RawLiteral* LiteralPool::AddEntry(RawLiteral* literal) {
115   if (IsEmpty()) {
116     first_use_ = masm_->CursorOffset();
117     SetNextRecommendedCheckpoint(NextRecommendedCheckpoint());
118     SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);
119   } else {
120     VIXL_ASSERT(masm_->CursorOffset() > first_use_);
121   }
122 
123   entries_.push_back(literal);
124   size_ += literal->size();
125 
126   return literal;
127 }
128 
129 
Reset()130 void VeneerPool::Reset() {
131   Pool::Reset();
132   unresolved_branches_.Reset();
133 }
134 
135 
Release()136 void VeneerPool::Release() {
137   if (--monitor_ == 0) {
138     VIXL_ASSERT(IsEmpty() ||
139                 masm_->CursorOffset() < unresolved_branches_.FirstLimit());
140   }
141 }
142 
143 
RegisterUnresolvedBranch(ptrdiff_t branch_pos,Label * label,ImmBranchType branch_type)144 void VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,
145                                           Label* label,
146                                           ImmBranchType branch_type) {
147   VIXL_ASSERT(!label->IsBound());
148   BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);
149   unresolved_branches_.insert(branch_info);
150   UpdateNextCheckPoint();
151   // TODO: In debug mode register the label with the assembler to make sure it
152   // is bound with masm Bind and not asm bind.
153 }
154 
155 
DeleteUnresolvedBranchInfoForLabel(Label * label)156 void VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {
157   if (IsEmpty()) {
158     VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);
159     return;
160   }
161 
162   if (label->IsLinked()) {
163     Label::LabelLinksIterator links_it(label);
164     for (; !links_it.Done(); links_it.Advance()) {
165       ptrdiff_t link_offset = *links_it.Current();
166       Instruction* link = masm_->InstructionAt(link_offset);
167 
168       // ADR instructions are not handled.
169       if (BranchTypeUsesVeneers(link->BranchType())) {
170         BranchInfo branch_info(link_offset, label, link->BranchType());
171         unresolved_branches_.erase(branch_info);
172       }
173     }
174   }
175 
176   UpdateNextCheckPoint();
177 }
178 
179 
ShouldEmitVeneer(int max_reachable_pc,size_t amount)180 bool VeneerPool::ShouldEmitVeneer(int max_reachable_pc, size_t amount) {
181   ptrdiff_t offset =
182       kPoolNonVeneerCodeSize + amount + MaxSize() + OtherPoolsMaxSize();
183   return (masm_->CursorOffset() + offset) > max_reachable_pc;
184 }
185 
186 
CheckEmitFor(size_t amount,EmitOption option)187 void VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {
188   if (IsEmpty()) return;
189 
190   VIXL_ASSERT(masm_->CursorOffset() < unresolved_branches_.FirstLimit());
191 
192   if (IsBlocked()) return;
193 
194   if (ShouldEmitVeneers(amount)) {
195     Emit(option, amount);
196   } else {
197     UpdateNextCheckPoint();
198   }
199 }
200 
201 
Emit(EmitOption option,size_t amount)202 void VeneerPool::Emit(EmitOption option, size_t amount) {
203   // There is an issue if we are asked to emit a blocked or empty pool.
204   VIXL_ASSERT(!IsBlocked());
205   VIXL_ASSERT(!IsEmpty());
206 
207   Label end;
208   if (option == kBranchRequired) {
209     InstructionAccurateScope scope(masm_, 1);
210     masm_->b(&end);
211   }
212 
213   // We want to avoid generating veneer pools too often, so generate veneers for
214   // branches that don't immediately require a veneer but will soon go out of
215   // range.
216   static const size_t kVeneerEmissionMargin = 1 * KBytes;
217 
218   for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {
219     BranchInfo* branch_info = it.Current();
220     if (ShouldEmitVeneer(branch_info->max_reachable_pc_,
221                          amount + kVeneerEmissionMargin)) {
222       InstructionAccurateScope scope(masm_, kVeneerCodeSize / kInstructionSize);
223       ptrdiff_t branch_pos = branch_info->pc_offset_;
224       Instruction* branch = masm_->InstructionAt(branch_pos);
225       Label* label = branch_info->label_;
226 
227       // Patch the branch to point to the current position, and emit a branch
228       // to the label.
229       Instruction* veneer = masm_->GetCursorAddress<Instruction*>();
230       branch->SetImmPCOffsetTarget(veneer);
231       masm_->b(label);
232 
233       // Update the label. The branch patched does not point to it any longer.
234       label->DeleteLink(branch_pos);
235 
236       it.DeleteCurrentAndAdvance();
237     } else {
238       it.AdvanceToNextType();
239     }
240   }
241 
242   UpdateNextCheckPoint();
243 
244   masm_->bind(&end);
245 }
246 
247 
EmissionCheckScope(MacroAssembler * masm,size_t size)248 EmissionCheckScope::EmissionCheckScope(MacroAssembler* masm, size_t size) {
249   if (masm) {
250     masm->EnsureEmitFor(size);
251 #ifdef VIXL_DEBUG
252     masm_ = masm;
253     masm->Bind(&start_);
254     size_ = size;
255     masm->AcquireBuffer();
256 #endif
257   }
258 }
259 
260 
~EmissionCheckScope()261 EmissionCheckScope::~EmissionCheckScope() {
262 #ifdef VIXL_DEBUG
263   if (masm_) {
264     masm_->ReleaseBuffer();
265     VIXL_ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) <= size_);
266   }
267 #endif
268 }
269 
270 
MacroAssembler(size_t capacity,PositionIndependentCodeOption pic)271 MacroAssembler::MacroAssembler(size_t capacity,
272                                PositionIndependentCodeOption pic)
273     : Assembler(capacity, pic),
274 #ifdef VIXL_DEBUG
275       allow_macro_instructions_(true),
276 #endif
277       sp_(sp),
278       tmp_list_(ip0, ip1),
279       fptmp_list_(d31),
280       literal_pool_(this),
281       veneer_pool_(this),
282       recommended_checkpoint_(Pool::kNoCheckpointRequired) {
283   checkpoint_ = NextCheckPoint();
284 }
285 
286 
MacroAssembler(byte * buffer,size_t capacity,PositionIndependentCodeOption pic)287 MacroAssembler::MacroAssembler(byte * buffer,
288                                size_t capacity,
289                                PositionIndependentCodeOption pic)
290     : Assembler(buffer, capacity, pic),
291 #ifdef VIXL_DEBUG
292       allow_macro_instructions_(true),
293 #endif
294       sp_(sp),
295       tmp_list_(ip0, ip1),
296       fptmp_list_(d31),
297       literal_pool_(this),
298       veneer_pool_(this),
299       recommended_checkpoint_(Pool::kNoCheckpointRequired) {
300   checkpoint_ = NextCheckPoint();
301 }
302 
303 
~MacroAssembler()304 MacroAssembler::~MacroAssembler() {
305 }
306 
307 
Reset()308 void MacroAssembler::Reset() {
309   Assembler::Reset();
310 
311   VIXL_ASSERT(!literal_pool_.IsBlocked());
312   literal_pool_.Reset();
313   veneer_pool_.Reset();
314 
315   checkpoint_ = NextCheckPoint();
316 }
317 
318 
FinalizeCode()319 void MacroAssembler::FinalizeCode() {
320   if (!literal_pool_.IsEmpty()) literal_pool_.Emit();
321   VIXL_ASSERT(veneer_pool_.IsEmpty());
322 
323   Assembler::FinalizeCode();
324 }
325 
326 
CheckEmitFor(size_t amount)327 void MacroAssembler::CheckEmitFor(size_t amount) {
328   ptrdiff_t offset = amount;
329 
330   literal_pool_.CheckEmitFor(amount);
331   veneer_pool_.CheckEmitFor(amount);
332   // Ensure there's enough space for the emit, keep in mind the cursor will
333   // have moved if a pool was emitted.
334   if ((CursorOffset() + offset) > BufferEndOffset()) {
335     EnsureSpaceFor(amount);
336   }
337 
338   checkpoint_ = NextCheckPoint();
339 }
340 
341 
MoveImmediateHelper(MacroAssembler * masm,const Register & rd,uint64_t imm)342 int MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,
343                                         const Register &rd,
344                                         uint64_t imm) {
345   bool emit_code = (masm != NULL);
346   VIXL_ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits());
347   // The worst case for size is mov 64-bit immediate to sp:
348   //  * up to 4 instructions to materialise the constant
349   //  * 1 instruction to move to sp
350   MacroEmissionCheckScope guard(masm);
351 
352   // Immediates on Aarch64 can be produced using an initial value, and zero to
353   // three move keep operations.
354   //
355   // Initial values can be generated with:
356   //  1. 64-bit move zero (movz).
357   //  2. 32-bit move inverted (movn).
358   //  3. 64-bit move inverted.
359   //  4. 32-bit orr immediate.
360   //  5. 64-bit orr immediate.
361   // Move-keep may then be used to modify each of the 16-bit half words.
362   //
363   // The code below supports all five initial value generators, and
364   // applying move-keep operations to move-zero and move-inverted initial
365   // values.
366 
367   // Try to move the immediate in one instruction, and if that fails, switch to
368   // using multiple instructions.
369   if (OneInstrMoveImmediateHelper(masm, rd, imm)) {
370     return 1;
371   } else {
372     int instruction_count = 0;
373     unsigned reg_size = rd.size();
374 
375     // Generic immediate case. Imm will be represented by
376     //   [imm3, imm2, imm1, imm0], where each imm is 16 bits.
377     // A move-zero or move-inverted is generated for the first non-zero or
378     // non-0xffff immX, and a move-keep for subsequent non-zero immX.
379 
380     uint64_t ignored_halfword = 0;
381     bool invert_move = false;
382     // If the number of 0xffff halfwords is greater than the number of 0x0000
383     // halfwords, it's more efficient to use move-inverted.
384     if (CountClearHalfWords(~imm, reg_size) >
385         CountClearHalfWords(imm, reg_size)) {
386       ignored_halfword = 0xffff;
387       invert_move = true;
388     }
389 
390     // Mov instructions can't move values into the stack pointer, so set up a
391     // temporary register, if needed.
392     UseScratchRegisterScope temps;
393     Register temp;
394     if (emit_code) {
395       temps.Open(masm);
396       temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
397     }
398 
399     // Iterate through the halfwords. Use movn/movz for the first non-ignored
400     // halfword, and movk for subsequent halfwords.
401     VIXL_ASSERT((reg_size % 16) == 0);
402     bool first_mov_done = false;
403     for (unsigned i = 0; i < (temp.size() / 16); i++) {
404       uint64_t imm16 = (imm >> (16 * i)) & 0xffff;
405       if (imm16 != ignored_halfword) {
406         if (!first_mov_done) {
407           if (invert_move) {
408             if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);
409             instruction_count++;
410           } else {
411             if (emit_code) masm->movz(temp, imm16, 16 * i);
412             instruction_count++;
413           }
414           first_mov_done = true;
415         } else {
416           // Construct a wider constant.
417           if (emit_code) masm->movk(temp, imm16, 16 * i);
418           instruction_count++;
419         }
420       }
421     }
422 
423     VIXL_ASSERT(first_mov_done);
424 
425     // Move the temporary if the original destination register was the stack
426     // pointer.
427     if (rd.IsSP()) {
428       if (emit_code) masm->mov(rd, temp);
429       instruction_count++;
430     }
431     return instruction_count;
432   }
433 }
434 
435 
OneInstrMoveImmediateHelper(MacroAssembler * masm,const Register & dst,int64_t imm)436 bool MacroAssembler::OneInstrMoveImmediateHelper(MacroAssembler* masm,
437                                                  const Register& dst,
438                                                  int64_t imm) {
439   bool emit_code = masm != NULL;
440   unsigned n, imm_s, imm_r;
441   int reg_size = dst.size();
442 
443   if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
444     // Immediate can be represented in a move zero instruction. Movz can't write
445     // to the stack pointer.
446     if (emit_code) {
447       masm->movz(dst, imm);
448     }
449     return true;
450   } else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
451     // Immediate can be represented in a move negative instruction. Movn can't
452     // write to the stack pointer.
453     if (emit_code) {
454       masm->movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
455     }
456     return true;
457   } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
458     // Immediate can be represented in a logical orr instruction.
459     VIXL_ASSERT(!dst.IsZero());
460     if (emit_code) {
461       masm->LogicalImmediate(
462           dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR);
463     }
464     return true;
465   }
466   return false;
467 }
468 
469 
B(Label * label,BranchType type,Register reg,int bit)470 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
471   VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&
472               ((bit == -1) || (type >= kBranchTypeFirstUsingBit)));
473   if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
474     B(static_cast<Condition>(type), label);
475   } else {
476     switch (type) {
477       case always:        B(label);              break;
478       case never:         break;
479       case reg_zero:      Cbz(reg, label);       break;
480       case reg_not_zero:  Cbnz(reg, label);      break;
481       case reg_bit_clear: Tbz(reg, bit, label);  break;
482       case reg_bit_set:   Tbnz(reg, bit, label); break;
483       default:
484         VIXL_UNREACHABLE();
485     }
486   }
487 }
488 
489 
B(Label * label)490 void MacroAssembler::B(Label* label) {
491   SingleEmissionCheckScope guard(this);
492   b(label);
493 }
494 
495 
B(Label * label,Condition cond)496 void MacroAssembler::B(Label* label, Condition cond) {
497   VIXL_ASSERT(allow_macro_instructions_);
498   VIXL_ASSERT((cond != al) && (cond != nv));
499   EmissionCheckScope guard(this, 2 * kInstructionSize);
500 
501   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
502     Label done;
503     b(&done, InvertCondition(cond));
504     b(label);
505     bind(&done);
506   } else {
507     if (!label->IsBound()) {
508       veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
509                                             label,
510                                             CondBranchType);
511     }
512     b(label, cond);
513   }
514 }
515 
516 
Cbnz(const Register & rt,Label * label)517 void MacroAssembler::Cbnz(const Register& rt, Label* label) {
518   VIXL_ASSERT(allow_macro_instructions_);
519   VIXL_ASSERT(!rt.IsZero());
520   EmissionCheckScope guard(this, 2 * kInstructionSize);
521 
522   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
523     Label done;
524     cbz(rt, &done);
525     b(label);
526     bind(&done);
527   } else {
528     if (!label->IsBound()) {
529       veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
530                                             label,
531                                             CompareBranchType);
532     }
533     cbnz(rt, label);
534   }
535 }
536 
537 
Cbz(const Register & rt,Label * label)538 void MacroAssembler::Cbz(const Register& rt, Label* label) {
539   VIXL_ASSERT(allow_macro_instructions_);
540   VIXL_ASSERT(!rt.IsZero());
541   EmissionCheckScope guard(this, 2 * kInstructionSize);
542 
543   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
544     Label done;
545     cbnz(rt, &done);
546     b(label);
547     bind(&done);
548   } else {
549     if (!label->IsBound()) {
550       veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
551                                             label,
552                                             CompareBranchType);
553     }
554     cbz(rt, label);
555   }
556 }
557 
558 
Tbnz(const Register & rt,unsigned bit_pos,Label * label)559 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
560   VIXL_ASSERT(allow_macro_instructions_);
561   VIXL_ASSERT(!rt.IsZero());
562   EmissionCheckScope guard(this, 2 * kInstructionSize);
563 
564   if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
565     Label done;
566     tbz(rt, bit_pos, &done);
567     b(label);
568     bind(&done);
569   } else {
570     if (!label->IsBound()) {
571       veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
572                                             label,
573                                             TestBranchType);
574     }
575     tbnz(rt, bit_pos, label);
576   }
577 }
578 
579 
Tbz(const Register & rt,unsigned bit_pos,Label * label)580 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
581   VIXL_ASSERT(allow_macro_instructions_);
582   VIXL_ASSERT(!rt.IsZero());
583   EmissionCheckScope guard(this, 2 * kInstructionSize);
584 
585   if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
586     Label done;
587     tbnz(rt, bit_pos, &done);
588     b(label);
589     bind(&done);
590   } else {
591     if (!label->IsBound()) {
592       veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
593                                             label,
594                                             TestBranchType);
595     }
596     tbz(rt, bit_pos, label);
597   }
598 }
599 
600 
Bind(Label * label)601 void MacroAssembler::Bind(Label* label) {
602   VIXL_ASSERT(allow_macro_instructions_);
603   veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
604   bind(label);
605 }
606 
607 
608 // Bind a label to a specified offset from the start of the buffer.
BindToOffset(Label * label,ptrdiff_t offset)609 void MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {
610   VIXL_ASSERT(allow_macro_instructions_);
611   veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
612   Assembler::BindToOffset(label, offset);
613 }
614 
615 
And(const Register & rd,const Register & rn,const Operand & operand)616 void MacroAssembler::And(const Register& rd,
617                          const Register& rn,
618                          const Operand& operand) {
619   VIXL_ASSERT(allow_macro_instructions_);
620   LogicalMacro(rd, rn, operand, AND);
621 }
622 
623 
Ands(const Register & rd,const Register & rn,const Operand & operand)624 void MacroAssembler::Ands(const Register& rd,
625                           const Register& rn,
626                           const Operand& operand) {
627   VIXL_ASSERT(allow_macro_instructions_);
628   LogicalMacro(rd, rn, operand, ANDS);
629 }
630 
631 
Tst(const Register & rn,const Operand & operand)632 void MacroAssembler::Tst(const Register& rn,
633                          const Operand& operand) {
634   VIXL_ASSERT(allow_macro_instructions_);
635   Ands(AppropriateZeroRegFor(rn), rn, operand);
636 }
637 
638 
Bic(const Register & rd,const Register & rn,const Operand & operand)639 void MacroAssembler::Bic(const Register& rd,
640                          const Register& rn,
641                          const Operand& operand) {
642   VIXL_ASSERT(allow_macro_instructions_);
643   LogicalMacro(rd, rn, operand, BIC);
644 }
645 
646 
Bics(const Register & rd,const Register & rn,const Operand & operand)647 void MacroAssembler::Bics(const Register& rd,
648                           const Register& rn,
649                           const Operand& operand) {
650   VIXL_ASSERT(allow_macro_instructions_);
651   LogicalMacro(rd, rn, operand, BICS);
652 }
653 
654 
Orr(const Register & rd,const Register & rn,const Operand & operand)655 void MacroAssembler::Orr(const Register& rd,
656                          const Register& rn,
657                          const Operand& operand) {
658   VIXL_ASSERT(allow_macro_instructions_);
659   LogicalMacro(rd, rn, operand, ORR);
660 }
661 
662 
Orn(const Register & rd,const Register & rn,const Operand & operand)663 void MacroAssembler::Orn(const Register& rd,
664                          const Register& rn,
665                          const Operand& operand) {
666   VIXL_ASSERT(allow_macro_instructions_);
667   LogicalMacro(rd, rn, operand, ORN);
668 }
669 
670 
Eor(const Register & rd,const Register & rn,const Operand & operand)671 void MacroAssembler::Eor(const Register& rd,
672                          const Register& rn,
673                          const Operand& operand) {
674   VIXL_ASSERT(allow_macro_instructions_);
675   LogicalMacro(rd, rn, operand, EOR);
676 }
677 
678 
Eon(const Register & rd,const Register & rn,const Operand & operand)679 void MacroAssembler::Eon(const Register& rd,
680                          const Register& rn,
681                          const Operand& operand) {
682   VIXL_ASSERT(allow_macro_instructions_);
683   LogicalMacro(rd, rn, operand, EON);
684 }
685 
686 
LogicalMacro(const Register & rd,const Register & rn,const Operand & operand,LogicalOp op)687 void MacroAssembler::LogicalMacro(const Register& rd,
688                                   const Register& rn,
689                                   const Operand& operand,
690                                   LogicalOp op) {
691   // The worst case for size is logical immediate to sp:
692   //  * up to 4 instructions to materialise the constant
693   //  * 1 instruction to do the operation
694   //  * 1 instruction to move to sp
695   MacroEmissionCheckScope guard(this);
696   UseScratchRegisterScope temps(this);
697 
698   if (operand.IsImmediate()) {
699     int64_t immediate = operand.immediate();
700     unsigned reg_size = rd.size();
701 
702     // If the operation is NOT, invert the operation and immediate.
703     if ((op & NOT) == NOT) {
704       op = static_cast<LogicalOp>(op & ~NOT);
705       immediate = ~immediate;
706     }
707 
708     // Ignore the top 32 bits of an immediate if we're moving to a W register.
709     if (rd.Is32Bits()) {
710       // Check that the top 32 bits are consistent.
711       VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||
712                   ((immediate >> kWRegSize) == -1));
713       immediate &= kWRegMask;
714     }
715 
716     VIXL_ASSERT(rd.Is64Bits() || is_uint32(immediate));
717 
718     // Special cases for all set or all clear immediates.
719     if (immediate == 0) {
720       switch (op) {
721         case AND:
722           Mov(rd, 0);
723           return;
724         case ORR:
725           VIXL_FALLTHROUGH();
726         case EOR:
727           Mov(rd, rn);
728           return;
729         case ANDS:
730           VIXL_FALLTHROUGH();
731         case BICS:
732           break;
733         default:
734           VIXL_UNREACHABLE();
735       }
736     } else if ((rd.Is64Bits() && (immediate == -1)) ||
737                (rd.Is32Bits() && (immediate == 0xffffffff))) {
738       switch (op) {
739         case AND:
740           Mov(rd, rn);
741           return;
742         case ORR:
743           Mov(rd, immediate);
744           return;
745         case EOR:
746           Mvn(rd, rn);
747           return;
748         case ANDS:
749           VIXL_FALLTHROUGH();
750         case BICS:
751           break;
752         default:
753           VIXL_UNREACHABLE();
754       }
755     }
756 
757     unsigned n, imm_s, imm_r;
758     if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
759       // Immediate can be encoded in the instruction.
760       LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
761     } else {
762       // Immediate can't be encoded: synthesize using move immediate.
763       Register temp = temps.AcquireSameSizeAs(rn);
764       Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
765 
766       if (rd.Is(sp)) {
767         // If rd is the stack pointer we cannot use it as the destination
768         // register so we use the temp register as an intermediate again.
769         Logical(temp, rn, imm_operand, op);
770         Mov(sp, temp);
771       } else {
772         Logical(rd, rn, imm_operand, op);
773       }
774     }
775   } else if (operand.IsExtendedRegister()) {
776     VIXL_ASSERT(operand.reg().size() <= rd.size());
777     // Add/sub extended supports shift <= 4. We want to support exactly the
778     // same modes here.
779     VIXL_ASSERT(operand.shift_amount() <= 4);
780     VIXL_ASSERT(operand.reg().Is64Bits() ||
781            ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
782 
783     temps.Exclude(operand.reg());
784     Register temp = temps.AcquireSameSizeAs(rn);
785     EmitExtendShift(temp, operand.reg(), operand.extend(),
786                     operand.shift_amount());
787     Logical(rd, rn, Operand(temp), op);
788   } else {
789     // The operand can be encoded in the instruction.
790     VIXL_ASSERT(operand.IsShiftedRegister());
791     Logical(rd, rn, operand, op);
792   }
793 }
794 
795 
Mov(const Register & rd,const Operand & operand,DiscardMoveMode discard_mode)796 void MacroAssembler::Mov(const Register& rd,
797                          const Operand& operand,
798                          DiscardMoveMode discard_mode) {
799   VIXL_ASSERT(allow_macro_instructions_);
800   // The worst case for size is mov immediate with up to 4 instructions.
801   MacroEmissionCheckScope guard(this);
802 
803   if (operand.IsImmediate()) {
804     // Call the macro assembler for generic immediates.
805     Mov(rd, operand.immediate());
806   } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
807     // Emit a shift instruction if moving a shifted register. This operation
808     // could also be achieved using an orr instruction (like orn used by Mvn),
809     // but using a shift instruction makes the disassembly clearer.
810     EmitShift(rd, operand.reg(), operand.shift(), operand.shift_amount());
811   } else if (operand.IsExtendedRegister()) {
812     // Emit an extend instruction if moving an extended register. This handles
813     // extend with post-shift operations, too.
814     EmitExtendShift(rd, operand.reg(), operand.extend(),
815                     operand.shift_amount());
816   } else {
817     // Otherwise, emit a register move only if the registers are distinct, or
818     // if they are not X registers.
819     //
820     // Note that mov(w0, w0) is not a no-op because it clears the top word of
821     // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W
822     // registers is not required to clear the top word of the X register. In
823     // this case, the instruction is discarded.
824     //
825     // If the sp is an operand, add #0 is emitted, otherwise, orr #0.
826     if (!rd.Is(operand.reg()) || (rd.Is32Bits() &&
827                                   (discard_mode == kDontDiscardForSameWReg))) {
828       mov(rd, operand.reg());
829     }
830   }
831 }
832 
833 
Movi16bitHelper(const VRegister & vd,uint64_t imm)834 void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {
835   VIXL_ASSERT(is_uint16(imm));
836   int byte1 = (imm & 0xff);
837   int byte2 = ((imm >> 8) & 0xff);
838   if (byte1 == byte2) {
839     movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);
840   } else if (byte1 == 0) {
841     movi(vd, byte2, LSL, 8);
842   } else if (byte2 == 0) {
843     movi(vd, byte1);
844   } else if (byte1 == 0xff) {
845     mvni(vd, ~byte2 & 0xff, LSL, 8);
846   } else if (byte2 == 0xff) {
847     mvni(vd, ~byte1 & 0xff);
848   } else {
849     UseScratchRegisterScope temps(this);
850     Register temp = temps.AcquireW();
851     movz(temp, imm);
852     dup(vd, temp);
853   }
854 }
855 
856 
Movi32bitHelper(const VRegister & vd,uint64_t imm)857 void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {
858   VIXL_ASSERT(is_uint32(imm));
859 
860   uint8_t bytes[sizeof(imm)];
861   memcpy(bytes, &imm, sizeof(imm));
862 
863   // All bytes are either 0x00 or 0xff.
864   {
865     bool all0orff = true;
866     for (int i = 0; i < 4; ++i) {
867       if ((bytes[i] != 0) && (bytes[i] != 0xff)) {
868         all0orff = false;
869         break;
870       }
871     }
872 
873     if (all0orff == true) {
874       movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));
875       return;
876     }
877   }
878 
879   // Of the 4 bytes, only one byte is non-zero.
880   for (int i = 0; i < 4; i++) {
881     if ((imm & (0xff << (i * 8))) == imm) {
882       movi(vd, bytes[i], LSL, i * 8);
883       return;
884     }
885   }
886 
887   // Of the 4 bytes, only one byte is not 0xff.
888   for (int i = 0; i < 4; i++) {
889     uint32_t mask = ~(0xff << (i * 8));
890     if ((imm & mask) == mask) {
891       mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);
892       return;
893     }
894   }
895 
896   // Immediate is of the form 0x00MMFFFF.
897   if ((imm & 0xff00ffff) == 0x0000ffff) {
898     movi(vd, bytes[2], MSL, 16);
899     return;
900   }
901 
902   // Immediate is of the form 0x0000MMFF.
903   if ((imm & 0xffff00ff) == 0x000000ff) {
904     movi(vd, bytes[1], MSL, 8);
905     return;
906   }
907 
908   // Immediate is of the form 0xFFMM0000.
909   if ((imm & 0xff00ffff) == 0xff000000) {
910     mvni(vd, ~bytes[2] & 0xff, MSL, 16);
911     return;
912   }
913   // Immediate is of the form 0xFFFFMM00.
914   if ((imm & 0xffff00ff) == 0xffff0000) {
915     mvni(vd, ~bytes[1] & 0xff, MSL, 8);
916     return;
917   }
918 
919   // Top and bottom 16-bits are equal.
920   if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {
921     Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);
922     return;
923   }
924 
925   // Default case.
926   {
927     UseScratchRegisterScope temps(this);
928     Register temp = temps.AcquireW();
929     Mov(temp, imm);
930     dup(vd, temp);
931   }
932 }
933 
934 
Movi64bitHelper(const VRegister & vd,uint64_t imm)935 void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
936   // All bytes are either 0x00 or 0xff.
937   {
938     bool all0orff = true;
939     for (int i = 0; i < 8; ++i) {
940       int byteval = (imm >> (i * 8)) & 0xff;
941       if (byteval != 0 && byteval != 0xff) {
942         all0orff = false;
943         break;
944       }
945     }
946     if (all0orff == true) {
947       movi(vd, imm);
948       return;
949     }
950   }
951 
952   // Top and bottom 32-bits are equal.
953   if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {
954     Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);
955     return;
956   }
957 
958   // Default case.
959   {
960     UseScratchRegisterScope temps(this);
961     Register temp = temps.AcquireX();
962     Mov(temp, imm);
963     if (vd.Is1D()) {
964       mov(vd.D(), 0, temp);
965     } else {
966       dup(vd.V2D(), temp);
967     }
968   }
969 }
970 
971 
Movi(const VRegister & vd,uint64_t imm,Shift shift,int shift_amount)972 void MacroAssembler::Movi(const VRegister& vd,
973                           uint64_t imm,
974                           Shift shift,
975                           int shift_amount) {
976   VIXL_ASSERT(allow_macro_instructions_);
977   MacroEmissionCheckScope guard(this);
978   if (shift_amount != 0 || shift != LSL) {
979     movi(vd, imm, shift, shift_amount);
980   } else if (vd.Is8B() || vd.Is16B()) {
981     // 8-bit immediate.
982     VIXL_ASSERT(is_uint8(imm));
983     movi(vd, imm);
984   } else if (vd.Is4H() || vd.Is8H()) {
985     // 16-bit immediate.
986     Movi16bitHelper(vd, imm);
987   } else if (vd.Is2S() || vd.Is4S()) {
988     // 32-bit immediate.
989     Movi32bitHelper(vd, imm);
990   } else {
991     // 64-bit immediate.
992     Movi64bitHelper(vd, imm);
993   }
994 }
995 
996 
Movi(const VRegister & vd,uint64_t hi,uint64_t lo)997 void MacroAssembler::Movi(const VRegister& vd,
998                           uint64_t hi,
999                           uint64_t lo) {
1000   // TODO: Move 128-bit values in a more efficient way.
1001   VIXL_ASSERT(vd.Is128Bits());
1002   UseScratchRegisterScope temps(this);
1003   Movi(vd.V2D(), lo);
1004   Register temp = temps.AcquireX();
1005   Mov(temp, hi);
1006   Ins(vd.V2D(), 1, temp);
1007 }
1008 
1009 
Mvn(const Register & rd,const Operand & operand)1010 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
1011   VIXL_ASSERT(allow_macro_instructions_);
1012   // The worst case for size is mvn immediate with up to 4 instructions.
1013   MacroEmissionCheckScope guard(this);
1014 
1015   if (operand.IsImmediate()) {
1016     // Call the macro assembler for generic immediates.
1017     Mvn(rd, operand.immediate());
1018   } else if (operand.IsExtendedRegister()) {
1019     UseScratchRegisterScope temps(this);
1020     temps.Exclude(operand.reg());
1021 
1022     // Emit two instructions for the extend case. This differs from Mov, as
1023     // the extend and invert can't be achieved in one instruction.
1024     Register temp = temps.AcquireSameSizeAs(rd);
1025     EmitExtendShift(temp, operand.reg(), operand.extend(),
1026                     operand.shift_amount());
1027     mvn(rd, Operand(temp));
1028   } else {
1029     // Otherwise, register and shifted register cases can be handled by the
1030     // assembler directly, using orn.
1031     mvn(rd, operand);
1032   }
1033 }
1034 
1035 
Mov(const Register & rd,uint64_t imm)1036 void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
1037   VIXL_ASSERT(allow_macro_instructions_);
1038   MoveImmediateHelper(this, rd, imm);
1039 }
1040 
1041 
Ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1042 void MacroAssembler::Ccmp(const Register& rn,
1043                           const Operand& operand,
1044                           StatusFlags nzcv,
1045                           Condition cond) {
1046   VIXL_ASSERT(allow_macro_instructions_);
1047   if (operand.IsImmediate() && (operand.immediate() < 0)) {
1048     ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN);
1049   } else {
1050     ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
1051   }
1052 }
1053 
1054 
Ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1055 void MacroAssembler::Ccmn(const Register& rn,
1056                           const Operand& operand,
1057                           StatusFlags nzcv,
1058                           Condition cond) {
1059   VIXL_ASSERT(allow_macro_instructions_);
1060   if (operand.IsImmediate() && (operand.immediate() < 0)) {
1061     ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP);
1062   } else {
1063     ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
1064   }
1065 }
1066 
1067 
ConditionalCompareMacro(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)1068 void MacroAssembler::ConditionalCompareMacro(const Register& rn,
1069                                              const Operand& operand,
1070                                              StatusFlags nzcv,
1071                                              Condition cond,
1072                                              ConditionalCompareOp op) {
1073   VIXL_ASSERT((cond != al) && (cond != nv));
1074   // The worst case for size is ccmp immediate:
1075   //  * up to 4 instructions to materialise the constant
1076   //  * 1 instruction for ccmp
1077   MacroEmissionCheckScope guard(this);
1078 
1079   if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) ||
1080       (operand.IsImmediate() && IsImmConditionalCompare(operand.immediate()))) {
1081     // The immediate can be encoded in the instruction, or the operand is an
1082     // unshifted register: call the assembler.
1083     ConditionalCompare(rn, operand, nzcv, cond, op);
1084   } else {
1085     UseScratchRegisterScope temps(this);
1086     // The operand isn't directly supported by the instruction: perform the
1087     // operation on a temporary register.
1088     Register temp = temps.AcquireSameSizeAs(rn);
1089     Mov(temp, operand);
1090     ConditionalCompare(rn, temp, nzcv, cond, op);
1091   }
1092 }
1093 
1094 
Csel(const Register & rd,const Register & rn,const Operand & operand,Condition cond)1095 void MacroAssembler::Csel(const Register& rd,
1096                           const Register& rn,
1097                           const Operand& operand,
1098                           Condition cond) {
1099   VIXL_ASSERT(allow_macro_instructions_);
1100   VIXL_ASSERT(!rd.IsZero());
1101   VIXL_ASSERT(!rn.IsZero());
1102   VIXL_ASSERT((cond != al) && (cond != nv));
1103   // The worst case for size is csel immediate:
1104   //  * up to 4 instructions to materialise the constant
1105   //  * 1 instruction for csel
1106   MacroEmissionCheckScope guard(this);
1107 
1108   if (operand.IsImmediate()) {
1109     // Immediate argument. Handle special cases of 0, 1 and -1 using zero
1110     // register.
1111     int64_t imm = operand.immediate();
1112     Register zr = AppropriateZeroRegFor(rn);
1113     if (imm == 0) {
1114       csel(rd, rn, zr, cond);
1115     } else if (imm == 1) {
1116       csinc(rd, rn, zr, cond);
1117     } else if (imm == -1) {
1118       csinv(rd, rn, zr, cond);
1119     } else {
1120       UseScratchRegisterScope temps(this);
1121       Register temp = temps.AcquireSameSizeAs(rn);
1122       Mov(temp, operand.immediate());
1123       csel(rd, rn, temp, cond);
1124     }
1125   } else if (operand.IsShiftedRegister() && (operand.shift_amount() == 0)) {
1126     // Unshifted register argument.
1127     csel(rd, rn, operand.reg(), cond);
1128   } else {
1129     // All other arguments.
1130     UseScratchRegisterScope temps(this);
1131     Register temp = temps.AcquireSameSizeAs(rn);
1132     Mov(temp, operand);
1133     csel(rd, rn, temp, cond);
1134   }
1135 }
1136 
1137 
Add(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1138 void MacroAssembler::Add(const Register& rd,
1139                          const Register& rn,
1140                          const Operand& operand,
1141                          FlagsUpdate S) {
1142   VIXL_ASSERT(allow_macro_instructions_);
1143   if (operand.IsImmediate() && (operand.immediate() < 0) &&
1144       IsImmAddSub(-operand.immediate())) {
1145     AddSubMacro(rd, rn, -operand.immediate(), S, SUB);
1146   } else {
1147     AddSubMacro(rd, rn, operand, S, ADD);
1148   }
1149 }
1150 
1151 
Adds(const Register & rd,const Register & rn,const Operand & operand)1152 void MacroAssembler::Adds(const Register& rd,
1153                           const Register& rn,
1154                           const Operand& operand) {
1155   Add(rd, rn, operand, SetFlags);
1156 }
1157 
1158 
Sub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1159 void MacroAssembler::Sub(const Register& rd,
1160                          const Register& rn,
1161                          const Operand& operand,
1162                          FlagsUpdate S) {
1163   VIXL_ASSERT(allow_macro_instructions_);
1164   if (operand.IsImmediate() && (operand.immediate() < 0) &&
1165       IsImmAddSub(-operand.immediate())) {
1166     AddSubMacro(rd, rn, -operand.immediate(), S, ADD);
1167   } else {
1168     AddSubMacro(rd, rn, operand, S, SUB);
1169   }
1170 }
1171 
1172 
Subs(const Register & rd,const Register & rn,const Operand & operand)1173 void MacroAssembler::Subs(const Register& rd,
1174                           const Register& rn,
1175                           const Operand& operand) {
1176   Sub(rd, rn, operand, SetFlags);
1177 }
1178 
1179 
Cmn(const Register & rn,const Operand & operand)1180 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
1181   VIXL_ASSERT(allow_macro_instructions_);
1182   Adds(AppropriateZeroRegFor(rn), rn, operand);
1183 }
1184 
1185 
Cmp(const Register & rn,const Operand & operand)1186 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
1187   VIXL_ASSERT(allow_macro_instructions_);
1188   Subs(AppropriateZeroRegFor(rn), rn, operand);
1189 }
1190 
1191 
Fcmp(const FPRegister & fn,double value,FPTrapFlags trap)1192 void MacroAssembler::Fcmp(const FPRegister& fn, double value,
1193                           FPTrapFlags trap) {
1194   VIXL_ASSERT(allow_macro_instructions_);
1195   // The worst case for size is:
1196   //  * 1 to materialise the constant, using literal pool if necessary
1197   //  * 1 instruction for fcmp{e}
1198   MacroEmissionCheckScope guard(this);
1199   if (value != 0.0) {
1200     UseScratchRegisterScope temps(this);
1201     FPRegister tmp = temps.AcquireSameSizeAs(fn);
1202     Fmov(tmp, value);
1203     FPCompareMacro(fn, tmp, trap);
1204   } else {
1205     FPCompareMacro(fn, value, trap);
1206   }
1207 }
1208 
1209 
Fcmpe(const FPRegister & fn,double value)1210 void MacroAssembler::Fcmpe(const FPRegister& fn, double value) {
1211   Fcmp(fn, value, EnableTrap);
1212 }
1213 
1214 
Fmov(VRegister vd,double imm)1215 void MacroAssembler::Fmov(VRegister vd, double imm) {
1216   VIXL_ASSERT(allow_macro_instructions_);
1217   // Floating point immediates are loaded through the literal pool.
1218   MacroEmissionCheckScope guard(this);
1219 
1220   if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1221     Fmov(vd, static_cast<float>(imm));
1222     return;
1223   }
1224 
1225   VIXL_ASSERT(vd.Is1D() || vd.Is2D());
1226   if (IsImmFP64(imm)) {
1227     fmov(vd, imm);
1228   } else {
1229     uint64_t rawbits = double_to_rawbits(imm);
1230     if (vd.IsScalar()) {
1231       if (rawbits == 0) {
1232         fmov(vd, xzr);
1233       } else {
1234         RawLiteral* literal = literal_pool_.Add(imm);
1235         ldr(vd, literal);
1236       }
1237     } else {
1238       // TODO: consider NEON support for load literal.
1239       Movi(vd, rawbits);
1240     }
1241   }
1242 }
1243 
1244 
Fmov(VRegister vd,float imm)1245 void MacroAssembler::Fmov(VRegister vd, float imm) {
1246   VIXL_ASSERT(allow_macro_instructions_);
1247   // Floating point immediates are loaded through the literal pool.
1248   MacroEmissionCheckScope guard(this);
1249 
1250   if (vd.Is1D() || vd.Is2D()) {
1251     Fmov(vd, static_cast<double>(imm));
1252     return;
1253   }
1254 
1255   VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
1256   if (IsImmFP32(imm)) {
1257     fmov(vd, imm);
1258   } else {
1259     uint32_t rawbits = float_to_rawbits(imm);
1260     if (vd.IsScalar()) {
1261       if (rawbits == 0) {
1262         fmov(vd, wzr);
1263       } else {
1264         RawLiteral* literal = literal_pool_.Add(imm);
1265         ldr(vd, literal);
1266       }
1267     } else {
1268       // TODO: consider NEON support for load literal.
1269       Movi(vd, rawbits);
1270     }
1271   }
1272 }
1273 
1274 
1275 
Neg(const Register & rd,const Operand & operand)1276 void MacroAssembler::Neg(const Register& rd,
1277                          const Operand& operand) {
1278   VIXL_ASSERT(allow_macro_instructions_);
1279   if (operand.IsImmediate()) {
1280     Mov(rd, -operand.immediate());
1281   } else {
1282     Sub(rd, AppropriateZeroRegFor(rd), operand);
1283   }
1284 }
1285 
1286 
Negs(const Register & rd,const Operand & operand)1287 void MacroAssembler::Negs(const Register& rd,
1288                           const Operand& operand) {
1289   VIXL_ASSERT(allow_macro_instructions_);
1290   Subs(rd, AppropriateZeroRegFor(rd), operand);
1291 }
1292 
1293 
TryOneInstrMoveImmediate(const Register & dst,int64_t imm)1294 bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
1295                                               int64_t imm) {
1296   return OneInstrMoveImmediateHelper(this, dst, imm);
1297 }
1298 
1299 
MoveImmediateForShiftedOp(const Register & dst,int64_t imm)1300 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
1301                                                   int64_t imm) {
1302   int reg_size = dst.size();
1303 
1304   // Encode the immediate in a single move instruction, if possible.
1305   if (TryOneInstrMoveImmediate(dst, imm)) {
1306     // The move was successful; nothing to do here.
1307   } else {
1308     // Pre-shift the immediate to the least-significant bits of the register.
1309     int shift_low = CountTrailingZeros(imm, reg_size);
1310     int64_t imm_low = imm >> shift_low;
1311 
1312     // Pre-shift the immediate to the most-significant bits of the register,
1313     // inserting set bits in the least-significant bits.
1314     int shift_high = CountLeadingZeros(imm, reg_size);
1315     int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
1316 
1317     if (TryOneInstrMoveImmediate(dst, imm_low)) {
1318       // The new immediate has been moved into the destination's low bits:
1319       // return a new leftward-shifting operand.
1320       return Operand(dst, LSL, shift_low);
1321     } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
1322       // The new immediate has been moved into the destination's high bits:
1323       // return a new rightward-shifting operand.
1324       return Operand(dst, LSR, shift_high);
1325     } else {
1326       Mov(dst, imm);
1327     }
1328   }
1329   return Operand(dst);
1330 }
1331 
1332 
ComputeAddress(const Register & dst,const MemOperand & mem_op)1333 void MacroAssembler::ComputeAddress(const Register& dst,
1334                                     const MemOperand& mem_op) {
1335   // We cannot handle pre-indexing or post-indexing.
1336   VIXL_ASSERT(mem_op.addrmode() == Offset);
1337   Register base = mem_op.base();
1338   if (mem_op.IsImmediateOffset()) {
1339     Add(dst, base, mem_op.offset());
1340   } else {
1341     VIXL_ASSERT(mem_op.IsRegisterOffset());
1342     Register reg_offset = mem_op.regoffset();
1343     Shift shift = mem_op.shift();
1344     Extend extend = mem_op.extend();
1345     if (shift == NO_SHIFT) {
1346       VIXL_ASSERT(extend != NO_EXTEND);
1347       Add(dst, base, Operand(reg_offset, extend, mem_op.shift_amount()));
1348     } else {
1349       VIXL_ASSERT(extend == NO_EXTEND);
1350       Add(dst, base, Operand(reg_offset, shift, mem_op.shift_amount()));
1351     }
1352   }
1353 }
1354 
1355 
AddSubMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)1356 void MacroAssembler::AddSubMacro(const Register& rd,
1357                                  const Register& rn,
1358                                  const Operand& operand,
1359                                  FlagsUpdate S,
1360                                  AddSubOp op) {
1361   // Worst case is add/sub immediate:
1362   //  * up to 4 instructions to materialise the constant
1363   //  * 1 instruction for add/sub
1364   MacroEmissionCheckScope guard(this);
1365 
1366   if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1367       (S == LeaveFlags)) {
1368     // The instruction would be a nop. Avoid generating useless code.
1369     return;
1370   }
1371 
1372   if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
1373       (rn.IsZero() && !operand.IsShiftedRegister())                ||
1374       (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1375     UseScratchRegisterScope temps(this);
1376     Register temp = temps.AcquireSameSizeAs(rn);
1377     if (operand.IsImmediate()) {
1378       Operand imm_operand =
1379           MoveImmediateForShiftedOp(temp, operand.immediate());
1380       AddSub(rd, rn, imm_operand, S, op);
1381     } else {
1382       Mov(temp, operand);
1383       AddSub(rd, rn, temp, S, op);
1384     }
1385   } else {
1386     AddSub(rd, rn, operand, S, op);
1387   }
1388 }
1389 
1390 
Adc(const Register & rd,const Register & rn,const Operand & operand)1391 void MacroAssembler::Adc(const Register& rd,
1392                          const Register& rn,
1393                          const Operand& operand) {
1394   VIXL_ASSERT(allow_macro_instructions_);
1395   AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1396 }
1397 
1398 
Adcs(const Register & rd,const Register & rn,const Operand & operand)1399 void MacroAssembler::Adcs(const Register& rd,
1400                           const Register& rn,
1401                           const Operand& operand) {
1402   VIXL_ASSERT(allow_macro_instructions_);
1403   AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
1404 }
1405 
1406 
Sbc(const Register & rd,const Register & rn,const Operand & operand)1407 void MacroAssembler::Sbc(const Register& rd,
1408                          const Register& rn,
1409                          const Operand& operand) {
1410   VIXL_ASSERT(allow_macro_instructions_);
1411   AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1412 }
1413 
1414 
Sbcs(const Register & rd,const Register & rn,const Operand & operand)1415 void MacroAssembler::Sbcs(const Register& rd,
1416                           const Register& rn,
1417                           const Operand& operand) {
1418   VIXL_ASSERT(allow_macro_instructions_);
1419   AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
1420 }
1421 
1422 
Ngc(const Register & rd,const Operand & operand)1423 void MacroAssembler::Ngc(const Register& rd,
1424                          const Operand& operand) {
1425   VIXL_ASSERT(allow_macro_instructions_);
1426   Register zr = AppropriateZeroRegFor(rd);
1427   Sbc(rd, zr, operand);
1428 }
1429 
1430 
Ngcs(const Register & rd,const Operand & operand)1431 void MacroAssembler::Ngcs(const Register& rd,
1432                          const Operand& operand) {
1433   VIXL_ASSERT(allow_macro_instructions_);
1434   Register zr = AppropriateZeroRegFor(rd);
1435   Sbcs(rd, zr, operand);
1436 }
1437 
1438 
AddSubWithCarryMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)1439 void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1440                                           const Register& rn,
1441                                           const Operand& operand,
1442                                           FlagsUpdate S,
1443                                           AddSubWithCarryOp op) {
1444   VIXL_ASSERT(rd.size() == rn.size());
1445   // Worst case is addc/subc immediate:
1446   //  * up to 4 instructions to materialise the constant
1447   //  * 1 instruction for add/sub
1448   MacroEmissionCheckScope guard(this);
1449   UseScratchRegisterScope temps(this);
1450 
1451   if (operand.IsImmediate() ||
1452       (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1453     // Add/sub with carry (immediate or ROR shifted register.)
1454     Register temp = temps.AcquireSameSizeAs(rn);
1455     Mov(temp, operand);
1456     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1457   } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
1458     // Add/sub with carry (shifted register).
1459     VIXL_ASSERT(operand.reg().size() == rd.size());
1460     VIXL_ASSERT(operand.shift() != ROR);
1461     VIXL_ASSERT(is_uintn(rd.size() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
1462                     operand.shift_amount()));
1463     temps.Exclude(operand.reg());
1464     Register temp = temps.AcquireSameSizeAs(rn);
1465     EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
1466     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1467   } else if (operand.IsExtendedRegister()) {
1468     // Add/sub with carry (extended register).
1469     VIXL_ASSERT(operand.reg().size() <= rd.size());
1470     // Add/sub extended supports a shift <= 4. We want to support exactly the
1471     // same modes.
1472     VIXL_ASSERT(operand.shift_amount() <= 4);
1473     VIXL_ASSERT(operand.reg().Is64Bits() ||
1474            ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
1475     temps.Exclude(operand.reg());
1476     Register temp = temps.AcquireSameSizeAs(rn);
1477     EmitExtendShift(temp, operand.reg(), operand.extend(),
1478                     operand.shift_amount());
1479     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1480   } else {
1481     // The addressing mode is directly supported by the instruction.
1482     AddSubWithCarry(rd, rn, operand, S, op);
1483   }
1484 }
1485 
1486 
1487 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP)                         \
1488 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) {  \
1489   VIXL_ASSERT(allow_macro_instructions_);                             \
1490   LoadStoreMacro(REG, addr, OP);                                      \
1491 }
LS_MACRO_LIST(DEFINE_FUNCTION)1492 LS_MACRO_LIST(DEFINE_FUNCTION)
1493 #undef DEFINE_FUNCTION
1494 
1495 
1496 void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
1497                                     const MemOperand& addr,
1498                                     LoadStoreOp op) {
1499   // Worst case is ldr/str pre/post index:
1500   //  * 1 instruction for ldr/str
1501   //  * up to 4 instructions to materialise the constant
1502   //  * 1 instruction to update the base
1503   MacroEmissionCheckScope guard(this);
1504 
1505   int64_t offset = addr.offset();
1506   unsigned access_size = CalcLSDataSize(op);
1507 
1508   // Check if an immediate offset fits in the immediate field of the
1509   // appropriate instruction. If not, emit two instructions to perform
1510   // the operation.
1511   if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
1512       !IsImmLSUnscaled(offset)) {
1513     // Immediate offset that can't be encoded using unsigned or unscaled
1514     // addressing modes.
1515     UseScratchRegisterScope temps(this);
1516     Register temp = temps.AcquireSameSizeAs(addr.base());
1517     Mov(temp, addr.offset());
1518     LoadStore(rt, MemOperand(addr.base(), temp), op);
1519   } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
1520     // Post-index beyond unscaled addressing range.
1521     LoadStore(rt, MemOperand(addr.base()), op);
1522     Add(addr.base(), addr.base(), Operand(offset));
1523   } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
1524     // Pre-index beyond unscaled addressing range.
1525     Add(addr.base(), addr.base(), Operand(offset));
1526     LoadStore(rt, MemOperand(addr.base()), op);
1527   } else {
1528     // Encodable in one load/store instruction.
1529     LoadStore(rt, addr, op);
1530   }
1531 }
1532 
1533 
1534 #define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP)  \
1535 void MacroAssembler::FN(const REGTYPE REG,           \
1536                         const REGTYPE REG2,          \
1537                         const MemOperand& addr) {    \
1538   VIXL_ASSERT(allow_macro_instructions_);            \
1539   LoadStorePairMacro(REG, REG2, addr, OP);           \
1540 }
LSPAIR_MACRO_LIST(DEFINE_FUNCTION)1541 LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
1542 #undef DEFINE_FUNCTION
1543 
1544 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
1545                                         const CPURegister& rt2,
1546                                         const MemOperand& addr,
1547                                         LoadStorePairOp op) {
1548   // TODO(all): Should we support register offset for load-store-pair?
1549   VIXL_ASSERT(!addr.IsRegisterOffset());
1550   // Worst case is ldp/stp immediate:
1551   //  * 1 instruction for ldp/stp
1552   //  * up to 4 instructions to materialise the constant
1553   //  * 1 instruction to update the base
1554   MacroEmissionCheckScope guard(this);
1555 
1556   int64_t offset = addr.offset();
1557   unsigned access_size = CalcLSPairDataSize(op);
1558 
1559   // Check if the offset fits in the immediate field of the appropriate
1560   // instruction. If not, emit two instructions to perform the operation.
1561   if (IsImmLSPair(offset, access_size)) {
1562     // Encodable in one load/store pair instruction.
1563     LoadStorePair(rt, rt2, addr, op);
1564   } else {
1565     Register base = addr.base();
1566     if (addr.IsImmediateOffset()) {
1567       UseScratchRegisterScope temps(this);
1568       Register temp = temps.AcquireSameSizeAs(base);
1569       Add(temp, base, offset);
1570       LoadStorePair(rt, rt2, MemOperand(temp), op);
1571     } else if (addr.IsPostIndex()) {
1572       LoadStorePair(rt, rt2, MemOperand(base), op);
1573       Add(base, base, offset);
1574     } else {
1575       VIXL_ASSERT(addr.IsPreIndex());
1576       Add(base, base, offset);
1577       LoadStorePair(rt, rt2, MemOperand(base), op);
1578     }
1579   }
1580 }
1581 
1582 
Prfm(PrefetchOperation op,const MemOperand & addr)1583 void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
1584   MacroEmissionCheckScope guard(this);
1585 
1586   // There are no pre- or post-index modes for prfm.
1587   VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
1588 
1589   // The access size is implicitly 8 bytes for all prefetch operations.
1590   unsigned size = kXRegSizeInBytesLog2;
1591 
1592   // Check if an immediate offset fits in the immediate field of the
1593   // appropriate instruction. If not, emit two instructions to perform
1594   // the operation.
1595   if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.offset(), size) &&
1596       !IsImmLSUnscaled(addr.offset())) {
1597     // Immediate offset that can't be encoded using unsigned or unscaled
1598     // addressing modes.
1599     UseScratchRegisterScope temps(this);
1600     Register temp = temps.AcquireSameSizeAs(addr.base());
1601     Mov(temp, addr.offset());
1602     Prefetch(op, MemOperand(addr.base(), temp));
1603   } else {
1604     // Simple register-offsets are encodable in one instruction.
1605     Prefetch(op, addr);
1606   }
1607 }
1608 
1609 
Push(const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)1610 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
1611                           const CPURegister& src2, const CPURegister& src3) {
1612   VIXL_ASSERT(allow_macro_instructions_);
1613   VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1614   VIXL_ASSERT(src0.IsValid());
1615 
1616   int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
1617   int size = src0.SizeInBytes();
1618 
1619   PrepareForPush(count, size);
1620   PushHelper(count, size, src0, src1, src2, src3);
1621 }
1622 
1623 
Pop(const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)1624 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1,
1625                          const CPURegister& dst2, const CPURegister& dst3) {
1626   // It is not valid to pop into the same register more than once in one
1627   // instruction, not even into the zero register.
1628   VIXL_ASSERT(allow_macro_instructions_);
1629   VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
1630   VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1631   VIXL_ASSERT(dst0.IsValid());
1632 
1633   int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
1634   int size = dst0.SizeInBytes();
1635 
1636   PrepareForPop(count, size);
1637   PopHelper(count, size, dst0, dst1, dst2, dst3);
1638 }
1639 
1640 
PushCPURegList(CPURegList registers)1641 void MacroAssembler::PushCPURegList(CPURegList registers) {
1642   VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1643   VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
1644   VIXL_ASSERT(allow_macro_instructions_);
1645 
1646   int reg_size = registers.RegisterSizeInBytes();
1647   PrepareForPush(registers.Count(), reg_size);
1648 
1649   // Bump the stack pointer and store two registers at the bottom.
1650   int size = registers.TotalSizeInBytes();
1651   const CPURegister& bottom_0 = registers.PopLowestIndex();
1652   const CPURegister& bottom_1 = registers.PopLowestIndex();
1653   if (bottom_0.IsValid() && bottom_1.IsValid()) {
1654     Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
1655   } else if (bottom_0.IsValid()) {
1656     Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
1657   }
1658 
1659   int offset = 2 * reg_size;
1660   while (!registers.IsEmpty()) {
1661     const CPURegister& src0 = registers.PopLowestIndex();
1662     const CPURegister& src1 = registers.PopLowestIndex();
1663     if (src1.IsValid()) {
1664       Stp(src0, src1, MemOperand(StackPointer(), offset));
1665     } else {
1666       Str(src0, MemOperand(StackPointer(), offset));
1667     }
1668     offset += 2 * reg_size;
1669   }
1670 }
1671 
1672 
PopCPURegList(CPURegList registers)1673 void MacroAssembler::PopCPURegList(CPURegList registers) {
1674   VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1675   VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
1676   VIXL_ASSERT(allow_macro_instructions_);
1677 
1678   int reg_size = registers.RegisterSizeInBytes();
1679   PrepareForPop(registers.Count(), reg_size);
1680 
1681 
1682   int size = registers.TotalSizeInBytes();
1683   const CPURegister& bottom_0 = registers.PopLowestIndex();
1684   const CPURegister& bottom_1 = registers.PopLowestIndex();
1685 
1686   int offset = 2 * reg_size;
1687   while (!registers.IsEmpty()) {
1688     const CPURegister& dst0 = registers.PopLowestIndex();
1689     const CPURegister& dst1 = registers.PopLowestIndex();
1690     if (dst1.IsValid()) {
1691       Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
1692     } else {
1693       Ldr(dst0, MemOperand(StackPointer(), offset));
1694     }
1695     offset += 2 * reg_size;
1696   }
1697 
1698   // Load the two registers at the bottom and drop the stack pointer.
1699   if (bottom_0.IsValid() && bottom_1.IsValid()) {
1700     Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
1701   } else if (bottom_0.IsValid()) {
1702     Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
1703   }
1704 }
1705 
1706 
PushMultipleTimes(int count,Register src)1707 void MacroAssembler::PushMultipleTimes(int count, Register src) {
1708   VIXL_ASSERT(allow_macro_instructions_);
1709   int size = src.SizeInBytes();
1710 
1711   PrepareForPush(count, size);
1712   // Push up to four registers at a time if possible because if the current
1713   // stack pointer is sp and the register size is 32, registers must be pushed
1714   // in blocks of four in order to maintain the 16-byte alignment for sp.
1715   while (count >= 4) {
1716     PushHelper(4, size, src, src, src, src);
1717     count -= 4;
1718   }
1719   if (count >= 2) {
1720     PushHelper(2, size, src, src, NoReg, NoReg);
1721     count -= 2;
1722   }
1723   if (count == 1) {
1724     PushHelper(1, size, src, NoReg, NoReg, NoReg);
1725     count -= 1;
1726   }
1727   VIXL_ASSERT(count == 0);
1728 }
1729 
1730 
PushHelper(int count,int size,const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)1731 void MacroAssembler::PushHelper(int count, int size,
1732                                 const CPURegister& src0,
1733                                 const CPURegister& src1,
1734                                 const CPURegister& src2,
1735                                 const CPURegister& src3) {
1736   // Ensure that we don't unintentionally modify scratch or debug registers.
1737   // Worst case for size is 2 stp.
1738   InstructionAccurateScope scope(this, 2,
1739                                  InstructionAccurateScope::kMaximumSize);
1740 
1741   VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1742   VIXL_ASSERT(size == src0.SizeInBytes());
1743 
1744   // When pushing multiple registers, the store order is chosen such that
1745   // Push(a, b) is equivalent to Push(a) followed by Push(b).
1746   switch (count) {
1747     case 1:
1748       VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
1749       str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
1750       break;
1751     case 2:
1752       VIXL_ASSERT(src2.IsNone() && src3.IsNone());
1753       stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
1754       break;
1755     case 3:
1756       VIXL_ASSERT(src3.IsNone());
1757       stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
1758       str(src0, MemOperand(StackPointer(), 2 * size));
1759       break;
1760     case 4:
1761       // Skip over 4 * size, then fill in the gap. This allows four W registers
1762       // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
1763       // all times.
1764       stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
1765       stp(src1, src0, MemOperand(StackPointer(), 2 * size));
1766       break;
1767     default:
1768       VIXL_UNREACHABLE();
1769   }
1770 }
1771 
1772 
PopHelper(int count,int size,const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)1773 void MacroAssembler::PopHelper(int count, int size,
1774                                const CPURegister& dst0,
1775                                const CPURegister& dst1,
1776                                const CPURegister& dst2,
1777                                const CPURegister& dst3) {
1778   // Ensure that we don't unintentionally modify scratch or debug registers.
1779   // Worst case for size is 2 ldp.
1780   InstructionAccurateScope scope(this, 2,
1781                                  InstructionAccurateScope::kMaximumSize);
1782 
1783   VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1784   VIXL_ASSERT(size == dst0.SizeInBytes());
1785 
1786   // When popping multiple registers, the load order is chosen such that
1787   // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
1788   switch (count) {
1789     case 1:
1790       VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
1791       ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
1792       break;
1793     case 2:
1794       VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
1795       ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
1796       break;
1797     case 3:
1798       VIXL_ASSERT(dst3.IsNone());
1799       ldr(dst2, MemOperand(StackPointer(), 2 * size));
1800       ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
1801       break;
1802     case 4:
1803       // Load the higher addresses first, then load the lower addresses and skip
1804       // the whole block in the second instruction. This allows four W registers
1805       // to be popped using sp, whilst maintaining 16-byte alignment for sp at
1806       // all times.
1807       ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
1808       ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
1809       break;
1810     default:
1811       VIXL_UNREACHABLE();
1812   }
1813 }
1814 
1815 
PrepareForPush(int count,int size)1816 void MacroAssembler::PrepareForPush(int count, int size) {
1817   if (sp.Is(StackPointer())) {
1818     // If the current stack pointer is sp, then it must be aligned to 16 bytes
1819     // on entry and the total size of the specified registers must also be a
1820     // multiple of 16 bytes.
1821     VIXL_ASSERT((count * size) % 16 == 0);
1822   } else {
1823     // Even if the current stack pointer is not the system stack pointer (sp),
1824     // the system stack pointer will still be modified in order to comply with
1825     // ABI rules about accessing memory below the system stack pointer.
1826     BumpSystemStackPointer(count * size);
1827   }
1828 }
1829 
1830 
PrepareForPop(int count,int size)1831 void MacroAssembler::PrepareForPop(int count, int size) {
1832   USE(count);
1833   USE(size);
1834   if (sp.Is(StackPointer())) {
1835     // If the current stack pointer is sp, then it must be aligned to 16 bytes
1836     // on entry and the total size of the specified registers must also be a
1837     // multiple of 16 bytes.
1838     VIXL_ASSERT((count * size) % 16 == 0);
1839   }
1840 }
1841 
Poke(const Register & src,const Operand & offset)1842 void MacroAssembler::Poke(const Register& src, const Operand& offset) {
1843   VIXL_ASSERT(allow_macro_instructions_);
1844   if (offset.IsImmediate()) {
1845     VIXL_ASSERT(offset.immediate() >= 0);
1846   }
1847 
1848   Str(src, MemOperand(StackPointer(), offset));
1849 }
1850 
1851 
Peek(const Register & dst,const Operand & offset)1852 void MacroAssembler::Peek(const Register& dst, const Operand& offset) {
1853   VIXL_ASSERT(allow_macro_instructions_);
1854   if (offset.IsImmediate()) {
1855     VIXL_ASSERT(offset.immediate() >= 0);
1856   }
1857 
1858   Ldr(dst, MemOperand(StackPointer(), offset));
1859 }
1860 
1861 
Claim(const Operand & size)1862 void MacroAssembler::Claim(const Operand& size) {
1863   VIXL_ASSERT(allow_macro_instructions_);
1864 
1865   if (size.IsZero()) {
1866     return;
1867   }
1868 
1869   if (size.IsImmediate()) {
1870     VIXL_ASSERT(size.immediate() > 0);
1871     if (sp.Is(StackPointer())) {
1872       VIXL_ASSERT((size.immediate() % 16) == 0);
1873     }
1874   }
1875 
1876   if (!sp.Is(StackPointer())) {
1877     BumpSystemStackPointer(size);
1878   }
1879 
1880   Sub(StackPointer(), StackPointer(), size);
1881 }
1882 
1883 
Drop(const Operand & size)1884 void MacroAssembler::Drop(const Operand& size) {
1885   VIXL_ASSERT(allow_macro_instructions_);
1886 
1887   if (size.IsZero()) {
1888     return;
1889   }
1890 
1891   if (size.IsImmediate()) {
1892     VIXL_ASSERT(size.immediate() > 0);
1893     if (sp.Is(StackPointer())) {
1894       VIXL_ASSERT((size.immediate() % 16) == 0);
1895     }
1896   }
1897 
1898   Add(StackPointer(), StackPointer(), size);
1899 }
1900 
1901 
PushCalleeSavedRegisters()1902 void MacroAssembler::PushCalleeSavedRegisters() {
1903   // Ensure that the macro-assembler doesn't use any scratch registers.
1904   // 10 stp will be emitted.
1905   // TODO(all): Should we use GetCalleeSaved and SavedFP.
1906   InstructionAccurateScope scope(this, 10);
1907 
1908   // This method must not be called unless the current stack pointer is sp.
1909   VIXL_ASSERT(sp.Is(StackPointer()));
1910 
1911   MemOperand tos(sp, -2 * kXRegSizeInBytes, PreIndex);
1912 
1913   stp(x29, x30, tos);
1914   stp(x27, x28, tos);
1915   stp(x25, x26, tos);
1916   stp(x23, x24, tos);
1917   stp(x21, x22, tos);
1918   stp(x19, x20, tos);
1919 
1920   stp(d14, d15, tos);
1921   stp(d12, d13, tos);
1922   stp(d10, d11, tos);
1923   stp(d8, d9, tos);
1924 }
1925 
1926 
PopCalleeSavedRegisters()1927 void MacroAssembler::PopCalleeSavedRegisters() {
1928   // Ensure that the macro-assembler doesn't use any scratch registers.
1929   // 10 ldp will be emitted.
1930   // TODO(all): Should we use GetCalleeSaved and SavedFP.
1931   InstructionAccurateScope scope(this, 10);
1932 
1933   // This method must not be called unless the current stack pointer is sp.
1934   VIXL_ASSERT(sp.Is(StackPointer()));
1935 
1936   MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
1937 
1938   ldp(d8, d9, tos);
1939   ldp(d10, d11, tos);
1940   ldp(d12, d13, tos);
1941   ldp(d14, d15, tos);
1942 
1943   ldp(x19, x20, tos);
1944   ldp(x21, x22, tos);
1945   ldp(x23, x24, tos);
1946   ldp(x25, x26, tos);
1947   ldp(x27, x28, tos);
1948   ldp(x29, x30, tos);
1949 }
1950 
LoadCPURegList(CPURegList registers,const MemOperand & src)1951 void MacroAssembler::LoadCPURegList(CPURegList registers,
1952                                     const MemOperand& src) {
1953   LoadStoreCPURegListHelper(kLoad, registers, src);
1954 }
1955 
StoreCPURegList(CPURegList registers,const MemOperand & dst)1956 void MacroAssembler::StoreCPURegList(CPURegList registers,
1957                                      const MemOperand& dst) {
1958   LoadStoreCPURegListHelper(kStore, registers, dst);
1959 }
1960 
1961 
LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,CPURegList registers,const MemOperand & mem)1962 void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
1963                                                CPURegList registers,
1964                                                const MemOperand& mem) {
1965   // We do not handle pre-indexing or post-indexing.
1966   VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
1967   VIXL_ASSERT(!registers.Overlaps(tmp_list_));
1968   VIXL_ASSERT(!registers.Overlaps(fptmp_list_));
1969   VIXL_ASSERT(!registers.IncludesAliasOf(sp));
1970 
1971   UseScratchRegisterScope temps(this);
1972 
1973   MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers,
1974                                                         mem,
1975                                                         &temps);
1976 
1977   while (registers.Count() >= 2) {
1978     const CPURegister& dst0 = registers.PopLowestIndex();
1979     const CPURegister& dst1 = registers.PopLowestIndex();
1980     if (op == kStore) {
1981       Stp(dst0, dst1, loc);
1982     } else {
1983       VIXL_ASSERT(op == kLoad);
1984       Ldp(dst0, dst1, loc);
1985     }
1986     loc.AddOffset(2 * registers.RegisterSizeInBytes());
1987   }
1988   if (!registers.IsEmpty()) {
1989     if (op == kStore) {
1990       Str(registers.PopLowestIndex(), loc);
1991     } else {
1992       VIXL_ASSERT(op == kLoad);
1993       Ldr(registers.PopLowestIndex(), loc);
1994     }
1995   }
1996 }
1997 
BaseMemOperandForLoadStoreCPURegList(const CPURegList & registers,const MemOperand & mem,UseScratchRegisterScope * scratch_scope)1998 MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
1999     const CPURegList& registers,
2000     const MemOperand& mem,
2001     UseScratchRegisterScope* scratch_scope) {
2002   // If necessary, pre-compute the base address for the accesses.
2003   if (mem.IsRegisterOffset()) {
2004     Register reg_base = scratch_scope->AcquireX();
2005     ComputeAddress(reg_base, mem);
2006     return MemOperand(reg_base);
2007 
2008   } else if (mem.IsImmediateOffset()) {
2009     int reg_size = registers.RegisterSizeInBytes();
2010     int total_size = registers.TotalSizeInBytes();
2011     int64_t min_offset = mem.offset();
2012     int64_t max_offset = mem.offset() + std::max(0, total_size - 2 * reg_size);
2013     if ((registers.Count() >= 2) &&
2014         (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
2015          !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
2016       Register reg_base = scratch_scope->AcquireX();
2017       ComputeAddress(reg_base, mem);
2018       return MemOperand(reg_base);
2019     }
2020   }
2021 
2022   return mem;
2023 }
2024 
BumpSystemStackPointer(const Operand & space)2025 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
2026   VIXL_ASSERT(!sp.Is(StackPointer()));
2027   // TODO: Several callers rely on this not using scratch registers, so we use
2028   // the assembler directly here. However, this means that large immediate
2029   // values of 'space' cannot be handled.
2030   InstructionAccurateScope scope(this, 1);
2031   sub(sp, StackPointer(), space);
2032 }
2033 
2034 
2035 // TODO(all): Fix printf for NEON registers, and resolve whether we should be
2036 // using FPRegister or VRegister here.
2037 
2038 // This is the main Printf implementation. All callee-saved registers are
2039 // preserved, but NZCV and the caller-saved registers may be clobbered.
PrintfNoPreserve(const char * format,const CPURegister & arg0,const CPURegister & arg1,const CPURegister & arg2,const CPURegister & arg3)2040 void MacroAssembler::PrintfNoPreserve(const char * format,
2041                                       const CPURegister& arg0,
2042                                       const CPURegister& arg1,
2043                                       const CPURegister& arg2,
2044                                       const CPURegister& arg3) {
2045   // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2046   // in most cases anyway, so this restriction shouldn't be too serious.
2047   VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
2048 
2049   // The provided arguments, and their proper PCS registers.
2050   CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
2051   CPURegister pcs[kPrintfMaxArgCount];
2052 
2053   int arg_count = kPrintfMaxArgCount;
2054 
2055   // The PCS varargs registers for printf. Note that x0 is used for the printf
2056   // format string.
2057   static const CPURegList kPCSVarargs =
2058       CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
2059   static const CPURegList kPCSVarargsFP =
2060       CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
2061 
2062   // We can use caller-saved registers as scratch values, except for the
2063   // arguments and the PCS registers where they might need to go.
2064   UseScratchRegisterScope temps(this);
2065   temps.Include(kCallerSaved);
2066   temps.Include(kCallerSavedV);
2067   temps.Exclude(kPCSVarargs);
2068   temps.Exclude(kPCSVarargsFP);
2069   temps.Exclude(arg0, arg1, arg2, arg3);
2070 
2071   // Copies of the arg lists that we can iterate through.
2072   CPURegList pcs_varargs = kPCSVarargs;
2073   CPURegList pcs_varargs_fp = kPCSVarargsFP;
2074 
2075   // Place the arguments. There are lots of clever tricks and optimizations we
2076   // could use here, but Printf is a debug tool so instead we just try to keep
2077   // it simple: Move each input that isn't already in the right place to a
2078   // scratch register, then move everything back.
2079   for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
2080     // Work out the proper PCS register for this argument.
2081     if (args[i].IsRegister()) {
2082       pcs[i] = pcs_varargs.PopLowestIndex().X();
2083       // We might only need a W register here. We need to know the size of the
2084       // argument so we can properly encode it for the simulator call.
2085       if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
2086     } else if (args[i].IsVRegister()) {
2087       // In C, floats are always cast to doubles for varargs calls.
2088       pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
2089     } else {
2090       VIXL_ASSERT(args[i].IsNone());
2091       arg_count = i;
2092       break;
2093     }
2094 
2095     // If the argument is already in the right place, leave it where it is.
2096     if (args[i].Aliases(pcs[i])) continue;
2097 
2098     // Otherwise, if the argument is in a PCS argument register, allocate an
2099     // appropriate scratch register and then move it out of the way.
2100     if (kPCSVarargs.IncludesAliasOf(args[i]) ||
2101         kPCSVarargsFP.IncludesAliasOf(args[i])) {
2102       if (args[i].IsRegister()) {
2103         Register old_arg = Register(args[i]);
2104         Register new_arg = temps.AcquireSameSizeAs(old_arg);
2105         Mov(new_arg, old_arg);
2106         args[i] = new_arg;
2107       } else {
2108         FPRegister old_arg = FPRegister(args[i]);
2109         FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
2110         Fmov(new_arg, old_arg);
2111         args[i] = new_arg;
2112       }
2113     }
2114   }
2115 
2116   // Do a second pass to move values into their final positions and perform any
2117   // conversions that may be required.
2118   for (int i = 0; i < arg_count; i++) {
2119     VIXL_ASSERT(pcs[i].type() == args[i].type());
2120     if (pcs[i].IsRegister()) {
2121       Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2122     } else {
2123       VIXL_ASSERT(pcs[i].IsVRegister());
2124       if (pcs[i].size() == args[i].size()) {
2125         Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
2126       } else {
2127         Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
2128       }
2129     }
2130   }
2131 
2132   // Load the format string into x0, as per the procedure-call standard.
2133   //
2134   // To make the code as portable as possible, the format string is encoded
2135   // directly in the instruction stream. It might be cleaner to encode it in a
2136   // literal pool, but since Printf is usually used for debugging, it is
2137   // beneficial for it to be minimally dependent on other features.
2138   temps.Exclude(x0);
2139   Label format_address;
2140   Adr(x0, &format_address);
2141 
2142   // Emit the format string directly in the instruction stream.
2143   {
2144     BlockPoolsScope scope(this);
2145     // Data emitted:
2146     //   branch
2147     //   strlen(format) + 1 (includes null termination)
2148     //   padding to next instruction
2149     //   unreachable
2150     EmissionCheckScope guard(
2151         this,
2152         AlignUp(strlen(format) + 1, kInstructionSize) + 2 * kInstructionSize);
2153     Label after_data;
2154     B(&after_data);
2155     Bind(&format_address);
2156     EmitString(format);
2157     Unreachable();
2158     Bind(&after_data);
2159   }
2160 
2161   // We don't pass any arguments on the stack, but we still need to align the C
2162   // stack pointer to a 16-byte boundary for PCS compliance.
2163   if (!sp.Is(StackPointer())) {
2164     Bic(sp, StackPointer(), 0xf);
2165   }
2166 
2167   // Actually call printf. This part needs special handling for the simulator,
2168   // since the system printf function will use a different instruction set and
2169   // the procedure-call standard will not be compatible.
2170 #ifdef USE_SIMULATOR
2171   {
2172     InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
2173     hlt(kPrintfOpcode);
2174     dc32(arg_count);          // kPrintfArgCountOffset
2175 
2176     // Determine the argument pattern.
2177     uint32_t arg_pattern_list = 0;
2178     for (int i = 0; i < arg_count; i++) {
2179       uint32_t arg_pattern;
2180       if (pcs[i].IsRegister()) {
2181         arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
2182       } else {
2183         VIXL_ASSERT(pcs[i].Is64Bits());
2184         arg_pattern = kPrintfArgD;
2185       }
2186       VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
2187       arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
2188     }
2189     dc32(arg_pattern_list);   // kPrintfArgPatternListOffset
2190   }
2191 #else
2192   Register tmp = temps.AcquireX();
2193   Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2194   Blr(tmp);
2195 #endif
2196 }
2197 
2198 
Printf(const char * format,CPURegister arg0,CPURegister arg1,CPURegister arg2,CPURegister arg3)2199 void MacroAssembler::Printf(const char * format,
2200                             CPURegister arg0,
2201                             CPURegister arg1,
2202                             CPURegister arg2,
2203                             CPURegister arg3) {
2204   // We can only print sp if it is the current stack pointer.
2205   if (!sp.Is(StackPointer())) {
2206     VIXL_ASSERT(!sp.Aliases(arg0));
2207     VIXL_ASSERT(!sp.Aliases(arg1));
2208     VIXL_ASSERT(!sp.Aliases(arg2));
2209     VIXL_ASSERT(!sp.Aliases(arg3));
2210   }
2211 
2212   // Make sure that the macro assembler doesn't try to use any of our arguments
2213   // as scratch registers.
2214   UseScratchRegisterScope exclude_all(this);
2215   exclude_all.ExcludeAll();
2216 
2217   // Preserve all caller-saved registers as well as NZCV.
2218   // If sp is the stack pointer, PushCPURegList asserts that the size of each
2219   // list is a multiple of 16 bytes.
2220   PushCPURegList(kCallerSaved);
2221   PushCPURegList(kCallerSavedV);
2222 
2223   { UseScratchRegisterScope temps(this);
2224     // We can use caller-saved registers as scratch values (except for argN).
2225     temps.Include(kCallerSaved);
2226     temps.Include(kCallerSavedV);
2227     temps.Exclude(arg0, arg1, arg2, arg3);
2228 
2229     // If any of the arguments are the current stack pointer, allocate a new
2230     // register for them, and adjust the value to compensate for pushing the
2231     // caller-saved registers.
2232     bool arg0_sp = StackPointer().Aliases(arg0);
2233     bool arg1_sp = StackPointer().Aliases(arg1);
2234     bool arg2_sp = StackPointer().Aliases(arg2);
2235     bool arg3_sp = StackPointer().Aliases(arg3);
2236     if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
2237       // Allocate a register to hold the original stack pointer value, to pass
2238       // to PrintfNoPreserve as an argument.
2239       Register arg_sp = temps.AcquireX();
2240       Add(arg_sp, StackPointer(),
2241           kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes());
2242       if (arg0_sp) arg0 = Register(arg_sp.code(), arg0.size());
2243       if (arg1_sp) arg1 = Register(arg_sp.code(), arg1.size());
2244       if (arg2_sp) arg2 = Register(arg_sp.code(), arg2.size());
2245       if (arg3_sp) arg3 = Register(arg_sp.code(), arg3.size());
2246     }
2247 
2248     // Preserve NZCV.
2249     Register tmp = temps.AcquireX();
2250     Mrs(tmp, NZCV);
2251     Push(tmp, xzr);
2252     temps.Release(tmp);
2253 
2254     PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2255 
2256     // Restore NZCV.
2257     tmp = temps.AcquireX();
2258     Pop(xzr, tmp);
2259     Msr(NZCV, tmp);
2260     temps.Release(tmp);
2261   }
2262 
2263   PopCPURegList(kCallerSavedV);
2264   PopCPURegList(kCallerSaved);
2265 }
2266 
Trace(TraceParameters parameters,TraceCommand command)2267 void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
2268   VIXL_ASSERT(allow_macro_instructions_);
2269 
2270 #ifdef USE_SIMULATOR
2271   // The arguments to the trace pseudo instruction need to be contiguous in
2272   // memory, so make sure we don't try to emit a literal pool.
2273   InstructionAccurateScope scope(this, kTraceLength / kInstructionSize);
2274 
2275   Label start;
2276   bind(&start);
2277 
2278   // Refer to simulator-a64.h for a description of the marker and its
2279   // arguments.
2280   hlt(kTraceOpcode);
2281 
2282   VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2283   dc32(parameters);
2284 
2285   VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2286   dc32(command);
2287 #else
2288   // Emit nothing on real hardware.
2289   USE(parameters);
2290   USE(command);
2291 #endif
2292 }
2293 
2294 
Log(TraceParameters parameters)2295 void MacroAssembler::Log(TraceParameters parameters) {
2296   VIXL_ASSERT(allow_macro_instructions_);
2297 
2298 #ifdef USE_SIMULATOR
2299   // The arguments to the log pseudo instruction need to be contiguous in
2300   // memory, so make sure we don't try to emit a literal pool.
2301   InstructionAccurateScope scope(this, kLogLength / kInstructionSize);
2302 
2303   Label start;
2304   bind(&start);
2305 
2306   // Refer to simulator-a64.h for a description of the marker and its
2307   // arguments.
2308   hlt(kLogOpcode);
2309 
2310   VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2311   dc32(parameters);
2312 #else
2313   // Emit nothing on real hardware.
2314   USE(parameters);
2315 #endif
2316 }
2317 
2318 
EnableInstrumentation()2319 void MacroAssembler::EnableInstrumentation() {
2320   VIXL_ASSERT(!isprint(InstrumentStateEnable));
2321   InstructionAccurateScope scope(this, 1);
2322   movn(xzr, InstrumentStateEnable);
2323 }
2324 
2325 
DisableInstrumentation()2326 void MacroAssembler::DisableInstrumentation() {
2327   VIXL_ASSERT(!isprint(InstrumentStateDisable));
2328   InstructionAccurateScope scope(this, 1);
2329   movn(xzr, InstrumentStateDisable);
2330 }
2331 
2332 
AnnotateInstrumentation(const char * marker_name)2333 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
2334   VIXL_ASSERT(strlen(marker_name) == 2);
2335 
2336   // We allow only printable characters in the marker names. Unprintable
2337   // characters are reserved for controlling features of the instrumentation.
2338   VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
2339 
2340   InstructionAccurateScope scope(this, 1);
2341   movn(xzr, (marker_name[1] << 8) | marker_name[0]);
2342 }
2343 
2344 
Open(MacroAssembler * masm)2345 void UseScratchRegisterScope::Open(MacroAssembler* masm) {
2346   VIXL_ASSERT(!initialised_);
2347   available_ = masm->TmpList();
2348   availablefp_ = masm->FPTmpList();
2349   old_available_ = available_->list();
2350   old_availablefp_ = availablefp_->list();
2351   VIXL_ASSERT(available_->type() == CPURegister::kRegister);
2352   VIXL_ASSERT(availablefp_->type() == CPURegister::kVRegister);
2353 #ifdef VIXL_DEBUG
2354   initialised_ = true;
2355 #endif
2356 }
2357 
2358 
Close()2359 void UseScratchRegisterScope::Close() {
2360   if (available_) {
2361     available_->set_list(old_available_);
2362     available_ = NULL;
2363   }
2364   if (availablefp_) {
2365     availablefp_->set_list(old_availablefp_);
2366     availablefp_ = NULL;
2367   }
2368 #ifdef VIXL_DEBUG
2369   initialised_ = false;
2370 #endif
2371 }
2372 
2373 
UseScratchRegisterScope(MacroAssembler * masm)2374 UseScratchRegisterScope::UseScratchRegisterScope(MacroAssembler* masm) {
2375 #ifdef VIXL_DEBUG
2376   initialised_ = false;
2377 #endif
2378   Open(masm);
2379 }
2380 
2381 // This allows deferred (and optional) initialisation of the scope.
UseScratchRegisterScope()2382 UseScratchRegisterScope::UseScratchRegisterScope()
2383     : available_(NULL), availablefp_(NULL),
2384       old_available_(0), old_availablefp_(0) {
2385 #ifdef VIXL_DEBUG
2386   initialised_ = false;
2387 #endif
2388 }
2389 
~UseScratchRegisterScope()2390 UseScratchRegisterScope::~UseScratchRegisterScope() {
2391   Close();
2392 }
2393 
2394 
IsAvailable(const CPURegister & reg) const2395 bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2396   return available_->IncludesAliasOf(reg) || availablefp_->IncludesAliasOf(reg);
2397 }
2398 
2399 
AcquireSameSizeAs(const Register & reg)2400 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
2401   int code = AcquireNextAvailable(available_).code();
2402   return Register(code, reg.size());
2403 }
2404 
2405 
AcquireSameSizeAs(const FPRegister & reg)2406 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
2407   int code = AcquireNextAvailable(availablefp_).code();
2408   return FPRegister(code, reg.size());
2409 }
2410 
2411 
Release(const CPURegister & reg)2412 void UseScratchRegisterScope::Release(const CPURegister& reg) {
2413   VIXL_ASSERT(initialised_);
2414   if (reg.IsRegister()) {
2415     ReleaseByCode(available_, reg.code());
2416   } else if (reg.IsFPRegister()) {
2417     ReleaseByCode(availablefp_, reg.code());
2418   } else {
2419     VIXL_ASSERT(reg.IsNone());
2420   }
2421 }
2422 
2423 
Include(const CPURegList & list)2424 void UseScratchRegisterScope::Include(const CPURegList& list) {
2425   VIXL_ASSERT(initialised_);
2426   if (list.type() == CPURegister::kRegister) {
2427     // Make sure that neither sp nor xzr are included the list.
2428     IncludeByRegList(available_, list.list() & ~(xzr.Bit() | sp.Bit()));
2429   } else {
2430     VIXL_ASSERT(list.type() == CPURegister::kVRegister);
2431     IncludeByRegList(availablefp_, list.list());
2432   }
2433 }
2434 
2435 
Include(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)2436 void UseScratchRegisterScope::Include(const Register& reg1,
2437                                       const Register& reg2,
2438                                       const Register& reg3,
2439                                       const Register& reg4) {
2440   VIXL_ASSERT(initialised_);
2441   RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2442   // Make sure that neither sp nor xzr are included the list.
2443   include &= ~(xzr.Bit() | sp.Bit());
2444 
2445   IncludeByRegList(available_, include);
2446 }
2447 
2448 
Include(const FPRegister & reg1,const FPRegister & reg2,const FPRegister & reg3,const FPRegister & reg4)2449 void UseScratchRegisterScope::Include(const FPRegister& reg1,
2450                                       const FPRegister& reg2,
2451                                       const FPRegister& reg3,
2452                                       const FPRegister& reg4) {
2453   RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2454   IncludeByRegList(availablefp_, include);
2455 }
2456 
2457 
Exclude(const CPURegList & list)2458 void UseScratchRegisterScope::Exclude(const CPURegList& list) {
2459   if (list.type() == CPURegister::kRegister) {
2460     ExcludeByRegList(available_, list.list());
2461   } else {
2462     VIXL_ASSERT(list.type() == CPURegister::kVRegister);
2463     ExcludeByRegList(availablefp_, list.list());
2464   }
2465 }
2466 
2467 
Exclude(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)2468 void UseScratchRegisterScope::Exclude(const Register& reg1,
2469                                       const Register& reg2,
2470                                       const Register& reg3,
2471                                       const Register& reg4) {
2472   RegList exclude = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2473   ExcludeByRegList(available_, exclude);
2474 }
2475 
2476 
Exclude(const FPRegister & reg1,const FPRegister & reg2,const FPRegister & reg3,const FPRegister & reg4)2477 void UseScratchRegisterScope::Exclude(const FPRegister& reg1,
2478                                       const FPRegister& reg2,
2479                                       const FPRegister& reg3,
2480                                       const FPRegister& reg4) {
2481   RegList excludefp = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2482   ExcludeByRegList(availablefp_, excludefp);
2483 }
2484 
2485 
Exclude(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)2486 void UseScratchRegisterScope::Exclude(const CPURegister& reg1,
2487                                       const CPURegister& reg2,
2488                                       const CPURegister& reg3,
2489                                       const CPURegister& reg4) {
2490   RegList exclude = 0;
2491   RegList excludefp = 0;
2492 
2493   const CPURegister regs[] = {reg1, reg2, reg3, reg4};
2494 
2495   for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
2496     if (regs[i].IsRegister()) {
2497       exclude |= regs[i].Bit();
2498     } else if (regs[i].IsFPRegister()) {
2499       excludefp |= regs[i].Bit();
2500     } else {
2501       VIXL_ASSERT(regs[i].IsNone());
2502     }
2503   }
2504 
2505   ExcludeByRegList(available_, exclude);
2506   ExcludeByRegList(availablefp_, excludefp);
2507 }
2508 
2509 
ExcludeAll()2510 void UseScratchRegisterScope::ExcludeAll() {
2511   ExcludeByRegList(available_, available_->list());
2512   ExcludeByRegList(availablefp_, availablefp_->list());
2513 }
2514 
2515 
AcquireNextAvailable(CPURegList * available)2516 CPURegister UseScratchRegisterScope::AcquireNextAvailable(
2517     CPURegList* available) {
2518   VIXL_CHECK(!available->IsEmpty());
2519   CPURegister result = available->PopLowestIndex();
2520   VIXL_ASSERT(!AreAliased(result, xzr, sp));
2521   return result;
2522 }
2523 
2524 
ReleaseByCode(CPURegList * available,int code)2525 void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
2526   ReleaseByRegList(available, static_cast<RegList>(1) << code);
2527 }
2528 
2529 
ReleaseByRegList(CPURegList * available,RegList regs)2530 void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
2531                                                RegList regs) {
2532   available->set_list(available->list() | regs);
2533 }
2534 
2535 
IncludeByRegList(CPURegList * available,RegList regs)2536 void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
2537                                                RegList regs) {
2538   available->set_list(available->list() | regs);
2539 }
2540 
2541 
ExcludeByRegList(CPURegList * available,RegList exclude)2542 void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
2543                                                RegList exclude) {
2544   available->set_list(available->list() & ~exclude);
2545 }
2546 
2547 }  // namespace vixl
2548