• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015, VIXL authors
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 "macro-assembler-aarch64.h"
28 
29 #include <cctype>
30 
31 namespace vixl {
32 namespace aarch64 {
33 
34 
Release()35 void Pool::Release() {
36   if (--monitor_ == 0) {
37     // Ensure the pool has not been blocked for too long.
38     VIXL_ASSERT(masm_->GetCursorOffset() < checkpoint_);
39   }
40 }
41 
42 
SetNextCheckpoint(ptrdiff_t checkpoint)43 void Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {
44   masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);
45   checkpoint_ = checkpoint;
46 }
47 
48 
LiteralPool(MacroAssembler * masm)49 LiteralPool::LiteralPool(MacroAssembler* masm)
50     : Pool(masm),
51       size_(0),
52       first_use_(-1),
53       recommended_checkpoint_(kNoCheckpointRequired) {}
54 
55 
~LiteralPool()56 LiteralPool::~LiteralPool() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {
57   VIXL_ASSERT(IsEmpty());
58   VIXL_ASSERT(!IsBlocked());
59   for (std::vector<RawLiteral*>::iterator it = deleted_on_destruction_.begin();
60        it != deleted_on_destruction_.end();
61        it++) {
62     delete *it;
63   }
64 }
65 
66 
Reset()67 void LiteralPool::Reset() {
68   std::vector<RawLiteral*>::iterator it, end;
69   for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
70     RawLiteral* literal = *it;
71     if (literal->deletion_policy_ == RawLiteral::kDeletedOnPlacementByPool) {
72       delete literal;
73     }
74   }
75   entries_.clear();
76   size_ = 0;
77   first_use_ = -1;
78   Pool::Reset();
79   recommended_checkpoint_ = kNoCheckpointRequired;
80 }
81 
82 
CheckEmitFor(size_t amount,EmitOption option)83 void LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {
84   if (IsEmpty() || IsBlocked()) return;
85 
86   ptrdiff_t distance = masm_->GetCursorOffset() + amount - first_use_;
87   if (distance >= kRecommendedLiteralPoolRange) {
88     Emit(option);
89   }
90 }
91 
92 
CheckEmitForBranch(size_t range)93 void LiteralPool::CheckEmitForBranch(size_t range) {
94   if (IsEmpty() || IsBlocked()) return;
95   if (GetMaxSize() >= range) Emit();
96 }
97 
98 // We use a subclass to access the protected `ExactAssemblyScope` constructor
99 // giving us control over the pools. This allows us to use this scope within
100 // code emitting pools without creating a circular dependency.
101 // We keep the constructor private to restrict usage of this helper class.
102 class ExactAssemblyScopeWithoutPoolsCheck : public ExactAssemblyScope {
103  private:
ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler * masm,size_t size)104   ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler* masm, size_t size)
105       : ExactAssemblyScope(masm,
106                            size,
107                            ExactAssemblyScope::kExactSize,
108                            ExactAssemblyScope::kIgnorePools) {}
109 
110   friend void LiteralPool::Emit(LiteralPool::EmitOption);
111   friend void VeneerPool::Emit(VeneerPool::EmitOption, size_t);
112 };
113 
114 
Emit(EmitOption option)115 void LiteralPool::Emit(EmitOption option) {
116   // There is an issue if we are asked to emit a blocked or empty pool.
117   VIXL_ASSERT(!IsBlocked());
118   VIXL_ASSERT(!IsEmpty());
119 
120   size_t pool_size = GetSize();
121   size_t emit_size = pool_size;
122   if (option == kBranchRequired) emit_size += kInstructionSize;
123   Label end_of_pool;
124 
125   VIXL_ASSERT(emit_size % kInstructionSize == 0);
126   {
127     CodeBufferCheckScope guard(masm_,
128                                emit_size,
129                                CodeBufferCheckScope::kCheck,
130                                CodeBufferCheckScope::kExactSize);
131 #ifdef VIXL_DEBUG
132     // Also explicitly disallow usage of the `MacroAssembler` here.
133     masm_->SetAllowMacroInstructions(false);
134 #endif
135     if (option == kBranchRequired) {
136       ExactAssemblyScopeWithoutPoolsCheck eas_guard(masm_, kInstructionSize);
137       masm_->b(&end_of_pool);
138     }
139 
140     {
141       // Marker indicating the size of the literal pool in 32-bit words.
142       VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);
143       ExactAssemblyScopeWithoutPoolsCheck eas_guard(masm_, kInstructionSize);
144       masm_->ldr(xzr, static_cast<int>(pool_size / kWRegSizeInBytes));
145     }
146 
147     // Now populate the literal pool.
148     std::vector<RawLiteral*>::iterator it, end;
149     for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
150       VIXL_ASSERT((*it)->IsUsed());
151       masm_->place(*it);
152     }
153 
154     if (option == kBranchRequired) masm_->bind(&end_of_pool);
155 #ifdef VIXL_DEBUG
156     masm_->SetAllowMacroInstructions(true);
157 #endif
158   }
159 
160   Reset();
161 }
162 
163 
AddEntry(RawLiteral * literal)164 void LiteralPool::AddEntry(RawLiteral* literal) {
165   // A literal must be registered immediately before its first use. Here we
166   // cannot control that it is its first use, but we check no code has been
167   // emitted since its last use.
168   VIXL_ASSERT(masm_->GetCursorOffset() == literal->GetLastUse());
169 
170   UpdateFirstUse(masm_->GetCursorOffset());
171   VIXL_ASSERT(masm_->GetCursorOffset() >= first_use_);
172   entries_.push_back(literal);
173   size_ += literal->GetSize();
174 }
175 
176 
UpdateFirstUse(ptrdiff_t use_position)177 void LiteralPool::UpdateFirstUse(ptrdiff_t use_position) {
178   first_use_ = std::min(first_use_, use_position);
179   if (first_use_ == -1) {
180     first_use_ = use_position;
181     SetNextRecommendedCheckpoint(GetNextRecommendedCheckpoint());
182     SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);
183   } else {
184     VIXL_ASSERT(use_position > first_use_);
185   }
186 }
187 
188 
Reset()189 void VeneerPool::Reset() {
190   Pool::Reset();
191   unresolved_branches_.Reset();
192 }
193 
194 
Release()195 void VeneerPool::Release() {
196   if (--monitor_ == 0) {
197     VIXL_ASSERT(IsEmpty() || masm_->GetCursorOffset() <
198                                  unresolved_branches_.GetFirstLimit());
199   }
200 }
201 
202 
RegisterUnresolvedBranch(ptrdiff_t branch_pos,Label * label,ImmBranchType branch_type)203 void VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,
204                                           Label* label,
205                                           ImmBranchType branch_type) {
206   VIXL_ASSERT(!label->IsBound());
207   BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);
208   unresolved_branches_.insert(branch_info);
209   UpdateNextCheckPoint();
210   // TODO: In debug mode register the label with the assembler to make sure it
211   // is bound with masm Bind and not asm bind.
212 }
213 
214 
DeleteUnresolvedBranchInfoForLabel(Label * label)215 void VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {
216   if (IsEmpty()) {
217     VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);
218     return;
219   }
220 
221   if (label->IsLinked()) {
222     Label::LabelLinksIterator links_it(label);
223     for (; !links_it.Done(); links_it.Advance()) {
224       ptrdiff_t link_offset = *links_it.Current();
225       Instruction* link = masm_->GetInstructionAt(link_offset);
226 
227       // ADR instructions are not handled.
228       if (BranchTypeUsesVeneers(link->GetBranchType())) {
229         BranchInfo branch_info(link_offset, label, link->GetBranchType());
230         unresolved_branches_.erase(branch_info);
231       }
232     }
233   }
234 
235   UpdateNextCheckPoint();
236 }
237 
238 
ShouldEmitVeneer(int64_t first_unreacheable_pc,size_t amount)239 bool VeneerPool::ShouldEmitVeneer(int64_t first_unreacheable_pc,
240                                   size_t amount) {
241   ptrdiff_t offset =
242       kPoolNonVeneerCodeSize + amount + GetMaxSize() + GetOtherPoolsMaxSize();
243   return (masm_->GetCursorOffset() + offset) > first_unreacheable_pc;
244 }
245 
246 
CheckEmitFor(size_t amount,EmitOption option)247 void VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {
248   if (IsEmpty()) return;
249 
250   VIXL_ASSERT(masm_->GetCursorOffset() + kPoolNonVeneerCodeSize <
251               unresolved_branches_.GetFirstLimit());
252 
253   if (IsBlocked()) return;
254 
255   if (ShouldEmitVeneers(amount)) {
256     Emit(option, amount);
257   } else {
258     UpdateNextCheckPoint();
259   }
260 }
261 
262 
Emit(EmitOption option,size_t amount)263 void VeneerPool::Emit(EmitOption option, size_t amount) {
264   // There is an issue if we are asked to emit a blocked or empty pool.
265   VIXL_ASSERT(!IsBlocked());
266   VIXL_ASSERT(!IsEmpty());
267 
268   Label end;
269   if (option == kBranchRequired) {
270     ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
271     masm_->b(&end);
272   }
273 
274   // We want to avoid generating veneer pools too often, so generate veneers for
275   // branches that don't immediately require a veneer but will soon go out of
276   // range.
277   static const size_t kVeneerEmissionMargin = 1 * KBytes;
278 
279   for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {
280     BranchInfo* branch_info = it.Current();
281     if (ShouldEmitVeneer(branch_info->first_unreacheable_pc_,
282                          amount + kVeneerEmissionMargin)) {
283       CodeBufferCheckScope scope(masm_,
284                                  kVeneerCodeSize,
285                                  CodeBufferCheckScope::kCheck,
286                                  CodeBufferCheckScope::kExactSize);
287       ptrdiff_t branch_pos = branch_info->pc_offset_;
288       Instruction* branch = masm_->GetInstructionAt(branch_pos);
289       Label* label = branch_info->label_;
290 
291       // Patch the branch to point to the current position, and emit a branch
292       // to the label.
293       Instruction* veneer = masm_->GetCursorAddress<Instruction*>();
294       branch->SetImmPCOffsetTarget(veneer);
295       {
296         ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
297         masm_->b(label);
298       }
299 
300       // Update the label. The branch patched does not point to it any longer.
301       label->DeleteLink(branch_pos);
302 
303       it.DeleteCurrentAndAdvance();
304     } else {
305       it.AdvanceToNextType();
306     }
307   }
308 
309   UpdateNextCheckPoint();
310 
311   masm_->bind(&end);
312 }
313 
314 
MacroAssembler(PositionIndependentCodeOption pic)315 MacroAssembler::MacroAssembler(PositionIndependentCodeOption pic)
316     : Assembler(pic),
317 #ifdef VIXL_DEBUG
318       allow_macro_instructions_(true),
319 #endif
320       generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
321       sp_(sp),
322       tmp_list_(ip0, ip1),
323       v_tmp_list_(d31),
324       p_tmp_list_(CPURegList::Empty(CPURegister::kPRegister)),
325       current_scratch_scope_(NULL),
326       literal_pool_(this),
327       veneer_pool_(this),
328       recommended_checkpoint_(Pool::kNoCheckpointRequired),
329       fp_nan_propagation_(NoFPMacroNaNPropagationSelected) {
330   checkpoint_ = GetNextCheckPoint();
331 #ifndef VIXL_DEBUG
332   USE(allow_macro_instructions_);
333 #endif
334 }
335 
336 
MacroAssembler(size_t capacity,PositionIndependentCodeOption pic)337 MacroAssembler::MacroAssembler(size_t capacity,
338                                PositionIndependentCodeOption pic)
339     : Assembler(capacity, pic),
340 #ifdef VIXL_DEBUG
341       allow_macro_instructions_(true),
342 #endif
343       generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
344       sp_(sp),
345       tmp_list_(ip0, ip1),
346       v_tmp_list_(d31),
347       p_tmp_list_(CPURegList::Empty(CPURegister::kPRegister)),
348       current_scratch_scope_(NULL),
349       literal_pool_(this),
350       veneer_pool_(this),
351       recommended_checkpoint_(Pool::kNoCheckpointRequired),
352       fp_nan_propagation_(NoFPMacroNaNPropagationSelected) {
353   checkpoint_ = GetNextCheckPoint();
354 }
355 
356 
MacroAssembler(byte * buffer,size_t capacity,PositionIndependentCodeOption pic)357 MacroAssembler::MacroAssembler(byte* buffer,
358                                size_t capacity,
359                                PositionIndependentCodeOption pic)
360     : Assembler(buffer, capacity, pic),
361 #ifdef VIXL_DEBUG
362       allow_macro_instructions_(true),
363 #endif
364       generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
365       sp_(sp),
366       tmp_list_(ip0, ip1),
367       v_tmp_list_(d31),
368       p_tmp_list_(CPURegList::Empty(CPURegister::kPRegister)),
369       current_scratch_scope_(NULL),
370       literal_pool_(this),
371       veneer_pool_(this),
372       recommended_checkpoint_(Pool::kNoCheckpointRequired),
373       fp_nan_propagation_(NoFPMacroNaNPropagationSelected) {
374   checkpoint_ = GetNextCheckPoint();
375 }
376 
377 
~MacroAssembler()378 MacroAssembler::~MacroAssembler() {}
379 
380 
Reset()381 void MacroAssembler::Reset() {
382   Assembler::Reset();
383 
384   VIXL_ASSERT(!literal_pool_.IsBlocked());
385   literal_pool_.Reset();
386   veneer_pool_.Reset();
387 
388   checkpoint_ = GetNextCheckPoint();
389 }
390 
391 
FinalizeCode(FinalizeOption option)392 void MacroAssembler::FinalizeCode(FinalizeOption option) {
393   if (!literal_pool_.IsEmpty()) {
394     // The user may decide to emit more code after Finalize, emit a branch if
395     // that's the case.
396     literal_pool_.Emit(option == kUnreachable ? Pool::kNoBranchRequired
397                                               : Pool::kBranchRequired);
398   }
399   VIXL_ASSERT(veneer_pool_.IsEmpty());
400 
401   Assembler::FinalizeCode();
402 }
403 
404 
CheckEmitFor(size_t amount)405 void MacroAssembler::CheckEmitFor(size_t amount) {
406   CheckEmitPoolsFor(amount);
407   GetBuffer()->EnsureSpaceFor(amount);
408 }
409 
410 
CheckEmitPoolsFor(size_t amount)411 void MacroAssembler::CheckEmitPoolsFor(size_t amount) {
412   literal_pool_.CheckEmitFor(amount);
413   veneer_pool_.CheckEmitFor(amount);
414   checkpoint_ = GetNextCheckPoint();
415 }
416 
417 
MoveImmediateHelper(MacroAssembler * masm,const Register & rd,uint64_t imm)418 int MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,
419                                         const Register& rd,
420                                         uint64_t imm) {
421   bool emit_code = (masm != NULL);
422   VIXL_ASSERT(IsUint32(imm) || IsInt32(imm) || rd.Is64Bits());
423   // The worst case for size is mov 64-bit immediate to sp:
424   //  * up to 4 instructions to materialise the constant
425   //  * 1 instruction to move to sp
426   MacroEmissionCheckScope guard(masm);
427 
428   // Immediates on Aarch64 can be produced using an initial value, and zero to
429   // three move keep operations.
430   //
431   // Initial values can be generated with:
432   //  1. 64-bit move zero (movz).
433   //  2. 32-bit move inverted (movn).
434   //  3. 64-bit move inverted.
435   //  4. 32-bit orr immediate.
436   //  5. 64-bit orr immediate.
437   // Move-keep may then be used to modify each of the 16-bit half words.
438   //
439   // The code below supports all five initial value generators, and
440   // applying move-keep operations to move-zero and move-inverted initial
441   // values.
442 
443   // Try to move the immediate in one instruction, and if that fails, switch to
444   // using multiple instructions.
445   if (OneInstrMoveImmediateHelper(masm, rd, imm)) {
446     return 1;
447   } else {
448     int instruction_count = 0;
449     unsigned reg_size = rd.GetSizeInBits();
450 
451     // Generic immediate case. Imm will be represented by
452     //   [imm3, imm2, imm1, imm0], where each imm is 16 bits.
453     // A move-zero or move-inverted is generated for the first non-zero or
454     // non-0xffff immX, and a move-keep for subsequent non-zero immX.
455 
456     uint64_t ignored_halfword = 0;
457     bool invert_move = false;
458     // If the number of 0xffff halfwords is greater than the number of 0x0000
459     // halfwords, it's more efficient to use move-inverted.
460     if (CountClearHalfWords(~imm, reg_size) >
461         CountClearHalfWords(imm, reg_size)) {
462       ignored_halfword = 0xffff;
463       invert_move = true;
464     }
465 
466     // Mov instructions can't move values into the stack pointer, so set up a
467     // temporary register, if needed.
468     UseScratchRegisterScope temps;
469     Register temp;
470     if (emit_code) {
471       temps.Open(masm);
472       temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
473     }
474 
475     // Iterate through the halfwords. Use movn/movz for the first non-ignored
476     // halfword, and movk for subsequent halfwords.
477     VIXL_ASSERT((reg_size % 16) == 0);
478     bool first_mov_done = false;
479     for (unsigned i = 0; i < (reg_size / 16); i++) {
480       uint64_t imm16 = (imm >> (16 * i)) & 0xffff;
481       if (imm16 != ignored_halfword) {
482         if (!first_mov_done) {
483           if (invert_move) {
484             if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);
485             instruction_count++;
486           } else {
487             if (emit_code) masm->movz(temp, imm16, 16 * i);
488             instruction_count++;
489           }
490           first_mov_done = true;
491         } else {
492           // Construct a wider constant.
493           if (emit_code) masm->movk(temp, imm16, 16 * i);
494           instruction_count++;
495         }
496       }
497     }
498 
499     VIXL_ASSERT(first_mov_done);
500 
501     // Move the temporary if the original destination register was the stack
502     // pointer.
503     if (rd.IsSP()) {
504       if (emit_code) masm->mov(rd, temp);
505       instruction_count++;
506     }
507     return instruction_count;
508   }
509 }
510 
511 
B(Label * label,BranchType type,Register reg,int bit)512 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
513   VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&
514               ((bit == -1) || (type >= kBranchTypeFirstUsingBit)));
515   if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
516     B(static_cast<Condition>(type), label);
517   } else {
518     switch (type) {
519       case always:
520         B(label);
521         break;
522       case never:
523         break;
524       case reg_zero:
525         Cbz(reg, label);
526         break;
527       case reg_not_zero:
528         Cbnz(reg, label);
529         break;
530       case reg_bit_clear:
531         Tbz(reg, bit, label);
532         break;
533       case reg_bit_set:
534         Tbnz(reg, bit, label);
535         break;
536       default:
537         VIXL_UNREACHABLE();
538     }
539   }
540 }
541 
542 
B(Label * label)543 void MacroAssembler::B(Label* label) {
544   // We don't need to check the size of the literal pool, because the size of
545   // the literal pool is already bounded by the literal range, which is smaller
546   // than the range of this branch.
547   VIXL_ASSERT(Instruction::GetImmBranchForwardRange(UncondBranchType) >
548               Instruction::kLoadLiteralRange);
549   SingleEmissionCheckScope guard(this);
550   b(label);
551 }
552 
553 
B(Label * label,Condition cond)554 void MacroAssembler::B(Label* label, Condition cond) {
555   // We don't need to check the size of the literal pool, because the size of
556   // the literal pool is already bounded by the literal range, which is smaller
557   // than the range of this branch.
558   VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CondBranchType) >
559               Instruction::kLoadLiteralRange);
560   VIXL_ASSERT(allow_macro_instructions_);
561   VIXL_ASSERT((cond != al) && (cond != nv));
562   EmissionCheckScope guard(this, 2 * kInstructionSize);
563 
564   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
565     Label done;
566     b(&done, InvertCondition(cond));
567     b(label);
568     bind(&done);
569   } else {
570     if (!label->IsBound()) {
571       veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
572                                             label,
573                                             CondBranchType);
574     }
575     b(label, cond);
576   }
577 }
578 
579 
Cbnz(const Register & rt,Label * label)580 void MacroAssembler::Cbnz(const Register& rt, Label* label) {
581   // We don't need to check the size of the literal pool, because the size of
582   // the literal pool is already bounded by the literal range, which is smaller
583   // than the range of this branch.
584   VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CompareBranchType) >
585               Instruction::kLoadLiteralRange);
586   VIXL_ASSERT(allow_macro_instructions_);
587   VIXL_ASSERT(!rt.IsZero());
588   EmissionCheckScope guard(this, 2 * kInstructionSize);
589 
590   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
591     Label done;
592     cbz(rt, &done);
593     b(label);
594     bind(&done);
595   } else {
596     if (!label->IsBound()) {
597       veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
598                                             label,
599                                             CompareBranchType);
600     }
601     cbnz(rt, label);
602   }
603 }
604 
605 
Cbz(const Register & rt,Label * label)606 void MacroAssembler::Cbz(const Register& rt, Label* label) {
607   // We don't need to check the size of the literal pool, because the size of
608   // the literal pool is already bounded by the literal range, which is smaller
609   // than the range of this branch.
610   VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CompareBranchType) >
611               Instruction::kLoadLiteralRange);
612   VIXL_ASSERT(allow_macro_instructions_);
613   VIXL_ASSERT(!rt.IsZero());
614   EmissionCheckScope guard(this, 2 * kInstructionSize);
615 
616   if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
617     Label done;
618     cbnz(rt, &done);
619     b(label);
620     bind(&done);
621   } else {
622     if (!label->IsBound()) {
623       veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
624                                             label,
625                                             CompareBranchType);
626     }
627     cbz(rt, label);
628   }
629 }
630 
631 
Tbnz(const Register & rt,unsigned bit_pos,Label * label)632 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
633   // This is to avoid a situation where emitting a veneer for a TBZ/TBNZ branch
634   // can become impossible because we emit the literal pool first.
635   literal_pool_.CheckEmitForBranch(
636       Instruction::GetImmBranchForwardRange(TestBranchType));
637   VIXL_ASSERT(allow_macro_instructions_);
638   VIXL_ASSERT(!rt.IsZero());
639   EmissionCheckScope guard(this, 2 * kInstructionSize);
640 
641   if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
642     Label done;
643     tbz(rt, bit_pos, &done);
644     b(label);
645     bind(&done);
646   } else {
647     if (!label->IsBound()) {
648       veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
649                                             label,
650                                             TestBranchType);
651     }
652     tbnz(rt, bit_pos, label);
653   }
654 }
655 
656 
Tbz(const Register & rt,unsigned bit_pos,Label * label)657 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
658   // This is to avoid a situation where emitting a veneer for a TBZ/TBNZ branch
659   // can become impossible because we emit the literal pool first.
660   literal_pool_.CheckEmitForBranch(
661       Instruction::GetImmBranchForwardRange(TestBranchType));
662   VIXL_ASSERT(allow_macro_instructions_);
663   VIXL_ASSERT(!rt.IsZero());
664   EmissionCheckScope guard(this, 2 * kInstructionSize);
665 
666   if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
667     Label done;
668     tbnz(rt, bit_pos, &done);
669     b(label);
670     bind(&done);
671   } else {
672     if (!label->IsBound()) {
673       veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
674                                             label,
675                                             TestBranchType);
676     }
677     tbz(rt, bit_pos, label);
678   }
679 }
680 
Bind(Label * label,BranchTargetIdentifier id)681 void MacroAssembler::Bind(Label* label, BranchTargetIdentifier id) {
682   VIXL_ASSERT(allow_macro_instructions_);
683   veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
684   if (id == EmitBTI_none) {
685     bind(label);
686   } else {
687     // Emit this inside an ExactAssemblyScope to ensure there are no extra
688     // instructions between the bind and the target identifier instruction.
689     ExactAssemblyScope scope(this, kInstructionSize);
690     bind(label);
691     if (id == EmitPACIASP) {
692       paciasp();
693     } else if (id == EmitPACIBSP) {
694       pacibsp();
695     } else {
696       bti(id);
697     }
698   }
699 }
700 
701 // Bind a label to a specified offset from the start of the buffer.
BindToOffset(Label * label,ptrdiff_t offset)702 void MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {
703   VIXL_ASSERT(allow_macro_instructions_);
704   veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
705   Assembler::BindToOffset(label, offset);
706 }
707 
708 
And(const Register & rd,const Register & rn,const Operand & operand)709 void MacroAssembler::And(const Register& rd,
710                          const Register& rn,
711                          const Operand& operand) {
712   VIXL_ASSERT(allow_macro_instructions_);
713   LogicalMacro(rd, rn, operand, AND);
714 }
715 
716 
Ands(const Register & rd,const Register & rn,const Operand & operand)717 void MacroAssembler::Ands(const Register& rd,
718                           const Register& rn,
719                           const Operand& operand) {
720   VIXL_ASSERT(allow_macro_instructions_);
721   LogicalMacro(rd, rn, operand, ANDS);
722 }
723 
724 
Tst(const Register & rn,const Operand & operand)725 void MacroAssembler::Tst(const Register& rn, const Operand& operand) {
726   VIXL_ASSERT(allow_macro_instructions_);
727   Ands(AppropriateZeroRegFor(rn), rn, operand);
728 }
729 
730 
Bic(const Register & rd,const Register & rn,const Operand & operand)731 void MacroAssembler::Bic(const Register& rd,
732                          const Register& rn,
733                          const Operand& operand) {
734   VIXL_ASSERT(allow_macro_instructions_);
735   LogicalMacro(rd, rn, operand, BIC);
736 }
737 
738 
Bics(const Register & rd,const Register & rn,const Operand & operand)739 void MacroAssembler::Bics(const Register& rd,
740                           const Register& rn,
741                           const Operand& operand) {
742   VIXL_ASSERT(allow_macro_instructions_);
743   LogicalMacro(rd, rn, operand, BICS);
744 }
745 
746 
Orr(const Register & rd,const Register & rn,const Operand & operand)747 void MacroAssembler::Orr(const Register& rd,
748                          const Register& rn,
749                          const Operand& operand) {
750   VIXL_ASSERT(allow_macro_instructions_);
751   LogicalMacro(rd, rn, operand, ORR);
752 }
753 
754 
Orn(const Register & rd,const Register & rn,const Operand & operand)755 void MacroAssembler::Orn(const Register& rd,
756                          const Register& rn,
757                          const Operand& operand) {
758   VIXL_ASSERT(allow_macro_instructions_);
759   LogicalMacro(rd, rn, operand, ORN);
760 }
761 
762 
Eor(const Register & rd,const Register & rn,const Operand & operand)763 void MacroAssembler::Eor(const Register& rd,
764                          const Register& rn,
765                          const Operand& operand) {
766   VIXL_ASSERT(allow_macro_instructions_);
767   LogicalMacro(rd, rn, operand, EOR);
768 }
769 
770 
Eon(const Register & rd,const Register & rn,const Operand & operand)771 void MacroAssembler::Eon(const Register& rd,
772                          const Register& rn,
773                          const Operand& operand) {
774   VIXL_ASSERT(allow_macro_instructions_);
775   LogicalMacro(rd, rn, operand, EON);
776 }
777 
778 
LogicalMacro(const Register & rd,const Register & rn,const Operand & operand,LogicalOp op)779 void MacroAssembler::LogicalMacro(const Register& rd,
780                                   const Register& rn,
781                                   const Operand& operand,
782                                   LogicalOp op) {
783   // The worst case for size is logical immediate to sp:
784   //  * up to 4 instructions to materialise the constant
785   //  * 1 instruction to do the operation
786   //  * 1 instruction to move to sp
787   MacroEmissionCheckScope guard(this);
788   UseScratchRegisterScope temps(this);
789   // Use `rd` as a temp, if we can.
790   temps.Include(rd);
791   // We read `rn` after evaluating `operand`.
792   temps.Exclude(rn);
793   // It doesn't matter if `operand` is in `temps` (e.g. because it alises `rd`)
794   // because we don't need it after it is evaluated.
795 
796   if (operand.IsImmediate()) {
797     uint64_t immediate = operand.GetImmediate();
798     unsigned reg_size = rd.GetSizeInBits();
799 
800     // If the operation is NOT, invert the operation and immediate.
801     if ((op & NOT) == NOT) {
802       op = static_cast<LogicalOp>(op & ~NOT);
803       immediate = ~immediate;
804     }
805 
806     // Ignore the top 32 bits of an immediate if we're moving to a W register.
807     if (rd.Is32Bits()) {
808       // Check that the top 32 bits are consistent.
809       VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||
810                   ((immediate >> kWRegSize) == 0xffffffff));
811       immediate &= kWRegMask;
812     }
813 
814     VIXL_ASSERT(rd.Is64Bits() || IsUint32(immediate));
815 
816     // Special cases for all set or all clear immediates.
817     if (immediate == 0) {
818       switch (op) {
819         case AND:
820           Mov(rd, 0);
821           return;
822         case ORR:
823           VIXL_FALLTHROUGH();
824         case EOR:
825           Mov(rd, rn);
826           return;
827         case ANDS:
828           VIXL_FALLTHROUGH();
829         case BICS:
830           break;
831         default:
832           VIXL_UNREACHABLE();
833       }
834     } else if ((rd.Is64Bits() && (immediate == UINT64_C(0xffffffffffffffff))) ||
835                (rd.Is32Bits() && (immediate == UINT64_C(0x00000000ffffffff)))) {
836       switch (op) {
837         case AND:
838           Mov(rd, rn);
839           return;
840         case ORR:
841           Mov(rd, immediate);
842           return;
843         case EOR:
844           Mvn(rd, rn);
845           return;
846         case ANDS:
847           VIXL_FALLTHROUGH();
848         case BICS:
849           break;
850         default:
851           VIXL_UNREACHABLE();
852       }
853     }
854 
855     unsigned n, imm_s, imm_r;
856     if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
857       // Immediate can be encoded in the instruction.
858       LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
859     } else {
860       // Immediate can't be encoded: synthesize using move immediate.
861       Register temp = temps.AcquireSameSizeAs(rn);
862       VIXL_ASSERT(!temp.Aliases(rn));
863 
864       // If the left-hand input is the stack pointer, we can't pre-shift the
865       // immediate, as the encoding won't allow the subsequent post shift.
866       PreShiftImmMode mode = rn.IsSP() ? kNoShift : kAnyShift;
867       Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode);
868 
869       if (rd.Is(sp) || rd.Is(wsp)) {
870         // If rd is the stack pointer we cannot use it as the destination
871         // register so we use the temp register as an intermediate again.
872         Logical(temp, rn, imm_operand, op);
873         Mov(rd, temp);
874       } else {
875         Logical(rd, rn, imm_operand, op);
876       }
877     }
878   } else if (operand.IsExtendedRegister()) {
879     VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());
880     // Add/sub extended supports shift <= 4. We want to support exactly the
881     // same modes here.
882     VIXL_ASSERT(operand.GetShiftAmount() <= 4);
883     VIXL_ASSERT(
884         operand.GetRegister().Is64Bits() ||
885         ((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));
886 
887     Register temp = temps.AcquireSameSizeAs(rn);
888     VIXL_ASSERT(!temp.Aliases(rn));
889     EmitExtendShift(temp,
890                     operand.GetRegister(),
891                     operand.GetExtend(),
892                     operand.GetShiftAmount());
893     Logical(rd, rn, Operand(temp), op);
894   } else {
895     // The operand can be encoded in the instruction.
896     VIXL_ASSERT(operand.IsShiftedRegister());
897     Logical(rd, rn, operand, op);
898   }
899 }
900 
901 
Mov(const Register & rd,const Operand & operand,DiscardMoveMode discard_mode)902 void MacroAssembler::Mov(const Register& rd,
903                          const Operand& operand,
904                          DiscardMoveMode discard_mode) {
905   VIXL_ASSERT(allow_macro_instructions_);
906   // The worst case for size is mov immediate with up to 4 instructions.
907   MacroEmissionCheckScope guard(this);
908 
909   if (operand.IsImmediate()) {
910     // Call the macro assembler for generic immediates.
911     Mov(rd, operand.GetImmediate());
912   } else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {
913     // Emit a shift instruction if moving a shifted register. This operation
914     // could also be achieved using an orr instruction (like orn used by Mvn),
915     // but using a shift instruction makes the disassembly clearer.
916     EmitShift(rd,
917               operand.GetRegister(),
918               operand.GetShift(),
919               operand.GetShiftAmount());
920   } else if (operand.IsExtendedRegister()) {
921     // Emit an extend instruction if moving an extended register. This handles
922     // extend with post-shift operations, too.
923     EmitExtendShift(rd,
924                     operand.GetRegister(),
925                     operand.GetExtend(),
926                     operand.GetShiftAmount());
927   } else {
928     Mov(rd, operand.GetRegister(), discard_mode);
929   }
930 }
931 
932 
Movi16bitHelper(const VRegister & vd,uint64_t imm)933 void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {
934   VIXL_ASSERT(IsUint16(imm));
935   int byte1 = (imm & 0xff);
936   int byte2 = ((imm >> 8) & 0xff);
937   if (byte1 == byte2) {
938     movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);
939   } else if (byte1 == 0) {
940     movi(vd, byte2, LSL, 8);
941   } else if (byte2 == 0) {
942     movi(vd, byte1);
943   } else if (byte1 == 0xff) {
944     mvni(vd, ~byte2 & 0xff, LSL, 8);
945   } else if (byte2 == 0xff) {
946     mvni(vd, ~byte1 & 0xff);
947   } else {
948     UseScratchRegisterScope temps(this);
949     Register temp = temps.AcquireW();
950     movz(temp, imm);
951     dup(vd, temp);
952   }
953 }
954 
955 
Movi32bitHelper(const VRegister & vd,uint64_t imm)956 void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {
957   VIXL_ASSERT(IsUint32(imm));
958 
959   uint8_t bytes[sizeof(imm)];
960   memcpy(bytes, &imm, sizeof(imm));
961 
962   // All bytes are either 0x00 or 0xff.
963   {
964     bool all0orff = true;
965     for (int i = 0; i < 4; ++i) {
966       if ((bytes[i] != 0) && (bytes[i] != 0xff)) {
967         all0orff = false;
968         break;
969       }
970     }
971 
972     if (all0orff == true) {
973       movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));
974       return;
975     }
976   }
977 
978   // Of the 4 bytes, only one byte is non-zero.
979   for (int i = 0; i < 4; i++) {
980     if ((imm & (0xff << (i * 8))) == imm) {
981       movi(vd, bytes[i], LSL, i * 8);
982       return;
983     }
984   }
985 
986   // Of the 4 bytes, only one byte is not 0xff.
987   for (int i = 0; i < 4; i++) {
988     uint32_t mask = ~(0xff << (i * 8));
989     if ((imm & mask) == mask) {
990       mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);
991       return;
992     }
993   }
994 
995   // Immediate is of the form 0x00MMFFFF.
996   if ((imm & 0xff00ffff) == 0x0000ffff) {
997     movi(vd, bytes[2], MSL, 16);
998     return;
999   }
1000 
1001   // Immediate is of the form 0x0000MMFF.
1002   if ((imm & 0xffff00ff) == 0x000000ff) {
1003     movi(vd, bytes[1], MSL, 8);
1004     return;
1005   }
1006 
1007   // Immediate is of the form 0xFFMM0000.
1008   if ((imm & 0xff00ffff) == 0xff000000) {
1009     mvni(vd, ~bytes[2] & 0xff, MSL, 16);
1010     return;
1011   }
1012   // Immediate is of the form 0xFFFFMM00.
1013   if ((imm & 0xffff00ff) == 0xffff0000) {
1014     mvni(vd, ~bytes[1] & 0xff, MSL, 8);
1015     return;
1016   }
1017 
1018   // Top and bottom 16-bits are equal.
1019   if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {
1020     Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);
1021     return;
1022   }
1023 
1024   // Default case.
1025   {
1026     UseScratchRegisterScope temps(this);
1027     Register temp = temps.AcquireW();
1028     Mov(temp, imm);
1029     dup(vd, temp);
1030   }
1031 }
1032 
1033 
Movi64bitHelper(const VRegister & vd,uint64_t imm)1034 void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
1035   // All bytes are either 0x00 or 0xff.
1036   {
1037     bool all0orff = true;
1038     for (int i = 0; i < 8; ++i) {
1039       int byteval = (imm >> (i * 8)) & 0xff;
1040       if (byteval != 0 && byteval != 0xff) {
1041         all0orff = false;
1042         break;
1043       }
1044     }
1045     if (all0orff == true) {
1046       movi(vd, imm);
1047       return;
1048     }
1049   }
1050 
1051   // Top and bottom 32-bits are equal.
1052   if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {
1053     Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);
1054     return;
1055   }
1056 
1057   // Default case.
1058   {
1059     UseScratchRegisterScope temps(this);
1060     Register temp = temps.AcquireX();
1061     Mov(temp, imm);
1062     if (vd.Is1D()) {
1063       fmov(vd.D(), temp);
1064     } else {
1065       dup(vd.V2D(), temp);
1066     }
1067   }
1068 }
1069 
1070 
Movi(const VRegister & vd,uint64_t imm,Shift shift,int shift_amount)1071 void MacroAssembler::Movi(const VRegister& vd,
1072                           uint64_t imm,
1073                           Shift shift,
1074                           int shift_amount) {
1075   VIXL_ASSERT(allow_macro_instructions_);
1076   MacroEmissionCheckScope guard(this);
1077   if (shift_amount != 0 || shift != LSL) {
1078     movi(vd, imm, shift, shift_amount);
1079   } else if (vd.Is8B() || vd.Is16B()) {
1080     // 8-bit immediate.
1081     VIXL_ASSERT(IsUint8(imm));
1082     movi(vd, imm);
1083   } else if (vd.Is4H() || vd.Is8H()) {
1084     // 16-bit immediate.
1085     Movi16bitHelper(vd, imm);
1086   } else if (vd.Is2S() || vd.Is4S()) {
1087     // 32-bit immediate.
1088     Movi32bitHelper(vd, imm);
1089   } else {
1090     // 64-bit immediate.
1091     Movi64bitHelper(vd, imm);
1092   }
1093 }
1094 
1095 
Movi(const VRegister & vd,uint64_t hi,uint64_t lo)1096 void MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) {
1097   // TODO: Move 128-bit values in a more efficient way.
1098   VIXL_ASSERT(vd.Is128Bits());
1099   if (hi == lo) {
1100     Movi(vd.V2D(), lo);
1101     return;
1102   }
1103 
1104   Movi(vd.V1D(), lo);
1105 
1106   if (hi != 0) {
1107     UseScratchRegisterScope temps(this);
1108     // TODO: Figure out if using a temporary V register to materialise the
1109     // immediate is better.
1110     Register temp = temps.AcquireX();
1111     Mov(temp, hi);
1112     Ins(vd.V2D(), 1, temp);
1113   }
1114 }
1115 
1116 
Mvn(const Register & rd,const Operand & operand)1117 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
1118   VIXL_ASSERT(allow_macro_instructions_);
1119   // The worst case for size is mvn immediate with up to 4 instructions.
1120   MacroEmissionCheckScope guard(this);
1121 
1122   if (operand.IsImmediate()) {
1123     // Call the macro assembler for generic immediates.
1124     Mvn(rd, operand.GetImmediate());
1125   } else if (operand.IsExtendedRegister()) {
1126     // Emit two instructions for the extend case. This differs from Mov, as
1127     // the extend and invert can't be achieved in one instruction.
1128     EmitExtendShift(rd,
1129                     operand.GetRegister(),
1130                     operand.GetExtend(),
1131                     operand.GetShiftAmount());
1132     mvn(rd, rd);
1133   } else {
1134     // Otherwise, register and shifted register cases can be handled by the
1135     // assembler directly, using orn.
1136     mvn(rd, operand);
1137   }
1138 }
1139 
1140 
Mov(const Register & rd,uint64_t imm)1141 void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
1142   VIXL_ASSERT(allow_macro_instructions_);
1143   MoveImmediateHelper(this, rd, imm);
1144 }
1145 
1146 
Ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1147 void MacroAssembler::Ccmp(const Register& rn,
1148                           const Operand& operand,
1149                           StatusFlags nzcv,
1150                           Condition cond) {
1151   VIXL_ASSERT(allow_macro_instructions_);
1152   if (operand.IsImmediate()) {
1153     int64_t imm = operand.GetImmediate();
1154     if ((imm < 0) && CanBeNegated(imm)) {
1155       ConditionalCompareMacro(rn, -imm, nzcv, cond, CCMN);
1156       return;
1157     }
1158   }
1159   ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
1160 }
1161 
1162 
Ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1163 void MacroAssembler::Ccmn(const Register& rn,
1164                           const Operand& operand,
1165                           StatusFlags nzcv,
1166                           Condition cond) {
1167   VIXL_ASSERT(allow_macro_instructions_);
1168   if (operand.IsImmediate()) {
1169     int64_t imm = operand.GetImmediate();
1170     if ((imm < 0) && CanBeNegated(imm)) {
1171       ConditionalCompareMacro(rn, -imm, nzcv, cond, CCMP);
1172       return;
1173     }
1174   }
1175   ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
1176 }
1177 
1178 
ConditionalCompareMacro(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)1179 void MacroAssembler::ConditionalCompareMacro(const Register& rn,
1180                                              const Operand& operand,
1181                                              StatusFlags nzcv,
1182                                              Condition cond,
1183                                              ConditionalCompareOp op) {
1184   VIXL_ASSERT((cond != al) && (cond != nv));
1185   // The worst case for size is ccmp immediate:
1186   //  * up to 4 instructions to materialise the constant
1187   //  * 1 instruction for ccmp
1188   MacroEmissionCheckScope guard(this);
1189 
1190   if ((operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0)) ||
1191       (operand.IsImmediate() &&
1192        IsImmConditionalCompare(operand.GetImmediate()))) {
1193     // The immediate can be encoded in the instruction, or the operand is an
1194     // unshifted register: call the assembler.
1195     ConditionalCompare(rn, operand, nzcv, cond, op);
1196   } else {
1197     UseScratchRegisterScope temps(this);
1198     // The operand isn't directly supported by the instruction: perform the
1199     // operation on a temporary register.
1200     Register temp = temps.AcquireSameSizeAs(rn);
1201     Mov(temp, operand);
1202     ConditionalCompare(rn, temp, nzcv, cond, op);
1203   }
1204 }
1205 
1206 
CselHelper(MacroAssembler * masm,const Register & rd,Operand left,Operand right,Condition cond,bool * should_synthesise_left,bool * should_synthesise_right)1207 void MacroAssembler::CselHelper(MacroAssembler* masm,
1208                                 const Register& rd,
1209                                 Operand left,
1210                                 Operand right,
1211                                 Condition cond,
1212                                 bool* should_synthesise_left,
1213                                 bool* should_synthesise_right) {
1214   bool emit_code = (masm != NULL);
1215 
1216   VIXL_ASSERT(!emit_code || masm->allow_macro_instructions_);
1217   VIXL_ASSERT((cond != al) && (cond != nv));
1218   VIXL_ASSERT(!rd.IsZero() && !rd.IsSP());
1219   VIXL_ASSERT(left.IsImmediate() || !left.GetRegister().IsSP());
1220   VIXL_ASSERT(right.IsImmediate() || !right.GetRegister().IsSP());
1221 
1222   if (should_synthesise_left != NULL) *should_synthesise_left = false;
1223   if (should_synthesise_right != NULL) *should_synthesise_right = false;
1224 
1225   // The worst case for size occurs when the inputs are two non encodable
1226   // constants:
1227   //  * up to 4 instructions to materialise the left constant
1228   //  * up to 4 instructions to materialise the right constant
1229   //  * 1 instruction for csel
1230   EmissionCheckScope guard(masm, 9 * kInstructionSize);
1231   UseScratchRegisterScope temps;
1232   if (masm != NULL) {
1233     temps.Open(masm);
1234   }
1235 
1236   // Try to handle cases where both inputs are immediates.
1237   bool left_is_immediate = left.IsImmediate() || left.IsZero();
1238   bool right_is_immediate = right.IsImmediate() || right.IsZero();
1239   if (left_is_immediate && right_is_immediate &&
1240       CselSubHelperTwoImmediates(masm,
1241                                  rd,
1242                                  left.GetEquivalentImmediate(),
1243                                  right.GetEquivalentImmediate(),
1244                                  cond,
1245                                  should_synthesise_left,
1246                                  should_synthesise_right)) {
1247     return;
1248   }
1249 
1250   // Handle cases where one of the two inputs is -1, 0, or 1.
1251   bool left_is_small_immediate =
1252       left_is_immediate && ((-1 <= left.GetEquivalentImmediate()) &&
1253                             (left.GetEquivalentImmediate() <= 1));
1254   bool right_is_small_immediate =
1255       right_is_immediate && ((-1 <= right.GetEquivalentImmediate()) &&
1256                              (right.GetEquivalentImmediate() <= 1));
1257   if (right_is_small_immediate || left_is_small_immediate) {
1258     bool swapped_inputs = false;
1259     if (!right_is_small_immediate) {
1260       std::swap(left, right);
1261       cond = InvertCondition(cond);
1262       swapped_inputs = true;
1263     }
1264     CselSubHelperRightSmallImmediate(masm,
1265                                      &temps,
1266                                      rd,
1267                                      left,
1268                                      right,
1269                                      cond,
1270                                      swapped_inputs ? should_synthesise_right
1271                                                     : should_synthesise_left);
1272     return;
1273   }
1274 
1275   // Otherwise both inputs need to be available in registers. Synthesise them
1276   // if necessary and emit the `csel`.
1277   if (!left.IsPlainRegister()) {
1278     if (emit_code) {
1279       Register temp = temps.AcquireSameSizeAs(rd);
1280       masm->Mov(temp, left);
1281       left = temp;
1282     }
1283     if (should_synthesise_left != NULL) *should_synthesise_left = true;
1284   }
1285   if (!right.IsPlainRegister()) {
1286     if (emit_code) {
1287       Register temp = temps.AcquireSameSizeAs(rd);
1288       masm->Mov(temp, right);
1289       right = temp;
1290     }
1291     if (should_synthesise_right != NULL) *should_synthesise_right = true;
1292   }
1293   if (emit_code) {
1294     VIXL_ASSERT(left.IsPlainRegister() && right.IsPlainRegister());
1295     if (left.GetRegister().Is(right.GetRegister())) {
1296       masm->Mov(rd, left.GetRegister());
1297     } else {
1298       masm->csel(rd, left.GetRegister(), right.GetRegister(), cond);
1299     }
1300   }
1301 }
1302 
1303 
CselSubHelperTwoImmediates(MacroAssembler * masm,const Register & rd,int64_t left,int64_t right,Condition cond,bool * should_synthesise_left,bool * should_synthesise_right)1304 bool MacroAssembler::CselSubHelperTwoImmediates(MacroAssembler* masm,
1305                                                 const Register& rd,
1306                                                 int64_t left,
1307                                                 int64_t right,
1308                                                 Condition cond,
1309                                                 bool* should_synthesise_left,
1310                                                 bool* should_synthesise_right) {
1311   bool emit_code = (masm != NULL);
1312   if (should_synthesise_left != NULL) *should_synthesise_left = false;
1313   if (should_synthesise_right != NULL) *should_synthesise_right = false;
1314 
1315   if (left == right) {
1316     if (emit_code) masm->Mov(rd, left);
1317     return true;
1318   } else if (left == -right) {
1319     if (should_synthesise_right != NULL) *should_synthesise_right = true;
1320     if (emit_code) {
1321       masm->Mov(rd, right);
1322       masm->Cneg(rd, rd, cond);
1323     }
1324     return true;
1325   }
1326 
1327   if (CselSubHelperTwoOrderedImmediates(masm, rd, left, right, cond)) {
1328     return true;
1329   } else {
1330     std::swap(left, right);
1331     if (CselSubHelperTwoOrderedImmediates(masm,
1332                                           rd,
1333                                           left,
1334                                           right,
1335                                           InvertCondition(cond))) {
1336       return true;
1337     }
1338   }
1339 
1340   // TODO: Handle more situations. For example handle `csel rd, #5, #6, cond`
1341   // with `cinc`.
1342   return false;
1343 }
1344 
1345 
CselSubHelperTwoOrderedImmediates(MacroAssembler * masm,const Register & rd,int64_t left,int64_t right,Condition cond)1346 bool MacroAssembler::CselSubHelperTwoOrderedImmediates(MacroAssembler* masm,
1347                                                        const Register& rd,
1348                                                        int64_t left,
1349                                                        int64_t right,
1350                                                        Condition cond) {
1351   bool emit_code = (masm != NULL);
1352 
1353   if ((left == 1) && (right == 0)) {
1354     if (emit_code) masm->cset(rd, cond);
1355     return true;
1356   } else if ((left == -1) && (right == 0)) {
1357     if (emit_code) masm->csetm(rd, cond);
1358     return true;
1359   }
1360   return false;
1361 }
1362 
1363 
CselSubHelperRightSmallImmediate(MacroAssembler * masm,UseScratchRegisterScope * temps,const Register & rd,const Operand & left,const Operand & right,Condition cond,bool * should_synthesise_left)1364 void MacroAssembler::CselSubHelperRightSmallImmediate(
1365     MacroAssembler* masm,
1366     UseScratchRegisterScope* temps,
1367     const Register& rd,
1368     const Operand& left,
1369     const Operand& right,
1370     Condition cond,
1371     bool* should_synthesise_left) {
1372   bool emit_code = (masm != NULL);
1373   VIXL_ASSERT((right.IsImmediate() || right.IsZero()) &&
1374               (-1 <= right.GetEquivalentImmediate()) &&
1375               (right.GetEquivalentImmediate() <= 1));
1376   Register left_register;
1377 
1378   if (left.IsPlainRegister()) {
1379     left_register = left.GetRegister();
1380   } else {
1381     if (emit_code) {
1382       left_register = temps->AcquireSameSizeAs(rd);
1383       masm->Mov(left_register, left);
1384     }
1385     if (should_synthesise_left != NULL) *should_synthesise_left = true;
1386   }
1387   if (emit_code) {
1388     int64_t imm = right.GetEquivalentImmediate();
1389     Register zr = AppropriateZeroRegFor(rd);
1390     if (imm == 0) {
1391       masm->csel(rd, left_register, zr, cond);
1392     } else if (imm == 1) {
1393       masm->csinc(rd, left_register, zr, cond);
1394     } else {
1395       VIXL_ASSERT(imm == -1);
1396       masm->csinv(rd, left_register, zr, cond);
1397     }
1398   }
1399 }
1400 
1401 
Add(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1402 void MacroAssembler::Add(const Register& rd,
1403                          const Register& rn,
1404                          const Operand& operand,
1405                          FlagsUpdate S) {
1406   VIXL_ASSERT(allow_macro_instructions_);
1407   if (operand.IsImmediate()) {
1408     int64_t imm = operand.GetImmediate();
1409     if ((imm < 0) && CanBeNegated(imm) && IsImmAddSub(-imm)) {
1410       AddSubMacro(rd, rn, -imm, S, SUB);
1411       return;
1412     }
1413   }
1414   AddSubMacro(rd, rn, operand, S, ADD);
1415 }
1416 
1417 
Adds(const Register & rd,const Register & rn,const Operand & operand)1418 void MacroAssembler::Adds(const Register& rd,
1419                           const Register& rn,
1420                           const Operand& operand) {
1421   Add(rd, rn, operand, SetFlags);
1422 }
1423 
1424 #define MINMAX(V)        \
1425   V(Smax, smax, IsInt8)  \
1426   V(Smin, smin, IsInt8)  \
1427   V(Umax, umax, IsUint8) \
1428   V(Umin, umin, IsUint8)
1429 
1430 #define VIXL_DEFINE_MASM_FUNC(MASM, ASM, RANGE)      \
1431   void MacroAssembler::MASM(const Register& rd,      \
1432                             const Register& rn,      \
1433                             const Operand& op) {     \
1434     VIXL_ASSERT(allow_macro_instructions_);          \
1435     if (op.IsImmediate()) {                          \
1436       int64_t imm = op.GetImmediate();               \
1437       if (!RANGE(imm)) {                             \
1438         UseScratchRegisterScope temps(this);         \
1439         Register temp = temps.AcquireSameSizeAs(rd); \
1440         Mov(temp, imm);                              \
1441         MASM(rd, rn, temp);                          \
1442         return;                                      \
1443       }                                              \
1444     }                                                \
1445     SingleEmissionCheckScope guard(this);            \
1446     ASM(rd, rn, op);                                 \
1447   }
MINMAX(VIXL_DEFINE_MASM_FUNC)1448 MINMAX(VIXL_DEFINE_MASM_FUNC)
1449 #undef VIXL_DEFINE_MASM_FUNC
1450 
1451 void MacroAssembler::St2g(const Register& rt, const MemOperand& addr) {
1452   VIXL_ASSERT(allow_macro_instructions_);
1453   SingleEmissionCheckScope guard(this);
1454   st2g(rt, addr);
1455 }
1456 
Stg(const Register & rt,const MemOperand & addr)1457 void MacroAssembler::Stg(const Register& rt, const MemOperand& addr) {
1458   VIXL_ASSERT(allow_macro_instructions_);
1459   SingleEmissionCheckScope guard(this);
1460   stg(rt, addr);
1461 }
1462 
Stgp(const Register & rt1,const Register & rt2,const MemOperand & addr)1463 void MacroAssembler::Stgp(const Register& rt1,
1464                           const Register& rt2,
1465                           const MemOperand& addr) {
1466   VIXL_ASSERT(allow_macro_instructions_);
1467   SingleEmissionCheckScope guard(this);
1468   stgp(rt1, rt2, addr);
1469 }
1470 
Stz2g(const Register & rt,const MemOperand & addr)1471 void MacroAssembler::Stz2g(const Register& rt, const MemOperand& addr) {
1472   VIXL_ASSERT(allow_macro_instructions_);
1473   SingleEmissionCheckScope guard(this);
1474   stz2g(rt, addr);
1475 }
1476 
Stzg(const Register & rt,const MemOperand & addr)1477 void MacroAssembler::Stzg(const Register& rt, const MemOperand& addr) {
1478   VIXL_ASSERT(allow_macro_instructions_);
1479   SingleEmissionCheckScope guard(this);
1480   stzg(rt, addr);
1481 }
1482 
Ldg(const Register & rt,const MemOperand & addr)1483 void MacroAssembler::Ldg(const Register& rt, const MemOperand& addr) {
1484   VIXL_ASSERT(allow_macro_instructions_);
1485   SingleEmissionCheckScope guard(this);
1486   ldg(rt, addr);
1487 }
1488 
Sub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1489 void MacroAssembler::Sub(const Register& rd,
1490                          const Register& rn,
1491                          const Operand& operand,
1492                          FlagsUpdate S) {
1493   VIXL_ASSERT(allow_macro_instructions_);
1494   if (operand.IsImmediate()) {
1495     int64_t imm = operand.GetImmediate();
1496     if ((imm < 0) && CanBeNegated(imm) && IsImmAddSub(-imm)) {
1497       AddSubMacro(rd, rn, -imm, S, ADD);
1498       return;
1499     }
1500   }
1501   AddSubMacro(rd, rn, operand, S, SUB);
1502 }
1503 
1504 
Subs(const Register & rd,const Register & rn,const Operand & operand)1505 void MacroAssembler::Subs(const Register& rd,
1506                           const Register& rn,
1507                           const Operand& operand) {
1508   Sub(rd, rn, operand, SetFlags);
1509 }
1510 
1511 
Cmn(const Register & rn,const Operand & operand)1512 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
1513   VIXL_ASSERT(allow_macro_instructions_);
1514   Adds(AppropriateZeroRegFor(rn), rn, operand);
1515 }
1516 
1517 
Cmp(const Register & rn,const Operand & operand)1518 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
1519   VIXL_ASSERT(allow_macro_instructions_);
1520   Subs(AppropriateZeroRegFor(rn), rn, operand);
1521 }
1522 
1523 
Fcmp(const VRegister & fn,double value,FPTrapFlags trap)1524 void MacroAssembler::Fcmp(const VRegister& fn, double value, FPTrapFlags trap) {
1525   VIXL_ASSERT(allow_macro_instructions_);
1526   // The worst case for size is:
1527   //  * 1 to materialise the constant, using literal pool if necessary
1528   //  * 1 instruction for fcmp{e}
1529   MacroEmissionCheckScope guard(this);
1530   if (value != 0.0) {
1531     UseScratchRegisterScope temps(this);
1532     VRegister tmp = temps.AcquireSameSizeAs(fn);
1533     Fmov(tmp, value);
1534     FPCompareMacro(fn, tmp, trap);
1535   } else {
1536     FPCompareMacro(fn, value, trap);
1537   }
1538 }
1539 
1540 
Fcmpe(const VRegister & fn,double value)1541 void MacroAssembler::Fcmpe(const VRegister& fn, double value) {
1542   Fcmp(fn, value, EnableTrap);
1543 }
1544 
1545 
Fmov(VRegister vd,double imm)1546 void MacroAssembler::Fmov(VRegister vd, double imm) {
1547   VIXL_ASSERT(allow_macro_instructions_);
1548   // Floating point immediates are loaded through the literal pool.
1549   MacroEmissionCheckScope guard(this);
1550   uint64_t rawbits = DoubleToRawbits(imm);
1551 
1552   if (rawbits == 0) {
1553     fmov(vd.D(), xzr);
1554     return;
1555   }
1556 
1557   if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {
1558     Fmov(vd, Float16(imm));
1559     return;
1560   }
1561 
1562   if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1563     Fmov(vd, static_cast<float>(imm));
1564     return;
1565   }
1566 
1567   VIXL_ASSERT(vd.Is1D() || vd.Is2D());
1568   if (IsImmFP64(rawbits)) {
1569     fmov(vd, imm);
1570   } else if (vd.IsScalar()) {
1571     ldr(vd,
1572         new Literal<double>(imm,
1573                             &literal_pool_,
1574                             RawLiteral::kDeletedOnPlacementByPool));
1575   } else {
1576     // TODO: consider NEON support for load literal.
1577     Movi(vd, rawbits);
1578   }
1579 }
1580 
1581 
Fmov(VRegister vd,float imm)1582 void MacroAssembler::Fmov(VRegister vd, float imm) {
1583   VIXL_ASSERT(allow_macro_instructions_);
1584   // Floating point immediates are loaded through the literal pool.
1585   MacroEmissionCheckScope guard(this);
1586   uint32_t rawbits = FloatToRawbits(imm);
1587 
1588   if (rawbits == 0) {
1589     fmov(vd.S(), wzr);
1590     return;
1591   }
1592 
1593   if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {
1594     Fmov(vd, Float16(imm));
1595     return;
1596   }
1597 
1598   if (vd.Is1D() || vd.Is2D()) {
1599     Fmov(vd, static_cast<double>(imm));
1600     return;
1601   }
1602 
1603   VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
1604   if (IsImmFP32(rawbits)) {
1605     fmov(vd, imm);
1606   } else if (vd.IsScalar()) {
1607     ldr(vd,
1608         new Literal<float>(imm,
1609                            &literal_pool_,
1610                            RawLiteral::kDeletedOnPlacementByPool));
1611   } else {
1612     // TODO: consider NEON support for load literal.
1613     Movi(vd, rawbits);
1614   }
1615 }
1616 
1617 
Fmov(VRegister vd,Float16 imm)1618 void MacroAssembler::Fmov(VRegister vd, Float16 imm) {
1619   VIXL_ASSERT(allow_macro_instructions_);
1620   MacroEmissionCheckScope guard(this);
1621 
1622   if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1623     Fmov(vd, FPToFloat(imm, kIgnoreDefaultNaN));
1624     return;
1625   }
1626 
1627   if (vd.Is1D() || vd.Is2D()) {
1628     Fmov(vd, FPToDouble(imm, kIgnoreDefaultNaN));
1629     return;
1630   }
1631 
1632   VIXL_ASSERT(vd.Is1H() || vd.Is4H() || vd.Is8H());
1633   uint16_t rawbits = Float16ToRawbits(imm);
1634   if (IsImmFP16(imm)) {
1635     fmov(vd, imm);
1636   } else {
1637     if (vd.IsScalar()) {
1638       if (rawbits == 0x0) {
1639         fmov(vd, wzr);
1640       } else {
1641         // We can use movz instead of the literal pool.
1642         UseScratchRegisterScope temps(this);
1643         Register temp = temps.AcquireW();
1644         Mov(temp, rawbits);
1645         Fmov(vd, temp);
1646       }
1647     } else {
1648       // TODO: consider NEON support for load literal.
1649       Movi(vd, static_cast<uint64_t>(rawbits));
1650     }
1651   }
1652 }
1653 
1654 
Neg(const Register & rd,const Operand & operand)1655 void MacroAssembler::Neg(const Register& rd, const Operand& operand) {
1656   VIXL_ASSERT(allow_macro_instructions_);
1657   if (operand.IsImmediate() && CanBeNegated(operand.GetImmediate())) {
1658     Mov(rd, -operand.GetImmediate());
1659   } else {
1660     Sub(rd, AppropriateZeroRegFor(rd), operand);
1661   }
1662 }
1663 
1664 
Negs(const Register & rd,const Operand & operand)1665 void MacroAssembler::Negs(const Register& rd, const Operand& operand) {
1666   VIXL_ASSERT(allow_macro_instructions_);
1667   Subs(rd, AppropriateZeroRegFor(rd), operand);
1668 }
1669 
1670 
TryOneInstrMoveImmediate(const Register & dst,uint64_t imm)1671 bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
1672                                               uint64_t imm) {
1673   return OneInstrMoveImmediateHelper(this, dst, imm);
1674 }
1675 
1676 
MoveImmediateForShiftedOp(const Register & dst,uint64_t imm,PreShiftImmMode mode)1677 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
1678                                                   uint64_t imm,
1679                                                   PreShiftImmMode mode) {
1680   int reg_size = dst.GetSizeInBits();
1681 
1682   // Encode the immediate in a single move instruction, if possible.
1683   if (TryOneInstrMoveImmediate(dst, imm)) {
1684     // The move was successful; nothing to do here.
1685   } else {
1686     // Pre-shift the immediate to the least-significant bits of the register.
1687     int shift_low = CountTrailingZeros(imm, reg_size);
1688     if (mode == kLimitShiftForSP) {
1689       // When applied to the stack pointer, the subsequent arithmetic operation
1690       // can use the extend form to shift left by a maximum of four bits. Right
1691       // shifts are not allowed, so we filter them out later before the new
1692       // immediate is tested.
1693       shift_low = std::min(shift_low, 4);
1694     }
1695     // TryOneInstrMoveImmediate handles `imm` with a value of zero, so shift_low
1696     // must lie in the range [0, 63], and the shifts below are well-defined.
1697     VIXL_ASSERT((shift_low >= 0) && (shift_low < 64));
1698     // imm_low = imm >> shift_low (with sign extension)
1699     uint64_t imm_low = ExtractSignedBitfield64(63, shift_low, imm);
1700 
1701     // Pre-shift the immediate to the most-significant bits of the register,
1702     // inserting set bits in the least-significant bits.
1703     int shift_high = CountLeadingZeros(imm, reg_size);
1704     VIXL_ASSERT((shift_high >= 0) && (shift_high < 64));
1705     uint64_t imm_high = (imm << shift_high) | GetUintMask(shift_high);
1706 
1707     if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) {
1708       // The new immediate has been moved into the destination's low bits:
1709       // return a new leftward-shifting operand.
1710       return Operand(dst, LSL, shift_low);
1711     } else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) {
1712       // The new immediate has been moved into the destination's high bits:
1713       // return a new rightward-shifting operand.
1714       return Operand(dst, LSR, shift_high);
1715     } else {
1716       Mov(dst, imm);
1717     }
1718   }
1719   return Operand(dst);
1720 }
1721 
1722 
Move(const GenericOperand & dst,const GenericOperand & src)1723 void MacroAssembler::Move(const GenericOperand& dst,
1724                           const GenericOperand& src) {
1725   if (dst.Equals(src)) {
1726     return;
1727   }
1728 
1729   VIXL_ASSERT(dst.IsValid() && src.IsValid());
1730 
1731   // The sizes of the operands must match exactly.
1732   VIXL_ASSERT(dst.GetSizeInBits() == src.GetSizeInBits());
1733   VIXL_ASSERT(dst.GetSizeInBits() <= kXRegSize);
1734   int operand_size = static_cast<int>(dst.GetSizeInBits());
1735 
1736   if (dst.IsCPURegister() && src.IsCPURegister()) {
1737     CPURegister dst_reg = dst.GetCPURegister();
1738     CPURegister src_reg = src.GetCPURegister();
1739     if (dst_reg.IsRegister() && src_reg.IsRegister()) {
1740       Mov(Register(dst_reg), Register(src_reg));
1741     } else if (dst_reg.IsVRegister() && src_reg.IsVRegister()) {
1742       Fmov(VRegister(dst_reg), VRegister(src_reg));
1743     } else {
1744       if (dst_reg.IsRegister()) {
1745         Fmov(Register(dst_reg), VRegister(src_reg));
1746       } else {
1747         Fmov(VRegister(dst_reg), Register(src_reg));
1748       }
1749     }
1750     return;
1751   }
1752 
1753   if (dst.IsMemOperand() && src.IsMemOperand()) {
1754     UseScratchRegisterScope temps(this);
1755     CPURegister temp = temps.AcquireCPURegisterOfSize(operand_size);
1756     Ldr(temp, src.GetMemOperand());
1757     Str(temp, dst.GetMemOperand());
1758     return;
1759   }
1760 
1761   if (dst.IsCPURegister()) {
1762     Ldr(dst.GetCPURegister(), src.GetMemOperand());
1763   } else {
1764     Str(src.GetCPURegister(), dst.GetMemOperand());
1765   }
1766 }
1767 
1768 
ComputeAddress(const Register & dst,const MemOperand & mem_op)1769 void MacroAssembler::ComputeAddress(const Register& dst,
1770                                     const MemOperand& mem_op) {
1771   // We cannot handle pre-indexing or post-indexing.
1772   VIXL_ASSERT(mem_op.GetAddrMode() == Offset);
1773   Register base = mem_op.GetBaseRegister();
1774   if (mem_op.IsImmediateOffset()) {
1775     Add(dst, base, mem_op.GetOffset());
1776   } else {
1777     VIXL_ASSERT(mem_op.IsRegisterOffset());
1778     Register reg_offset = mem_op.GetRegisterOffset();
1779     Shift shift = mem_op.GetShift();
1780     Extend extend = mem_op.GetExtend();
1781     if (shift == NO_SHIFT) {
1782       VIXL_ASSERT(extend != NO_EXTEND);
1783       Add(dst, base, Operand(reg_offset, extend, mem_op.GetShiftAmount()));
1784     } else {
1785       VIXL_ASSERT(extend == NO_EXTEND);
1786       Add(dst, base, Operand(reg_offset, shift, mem_op.GetShiftAmount()));
1787     }
1788   }
1789 }
1790 
1791 
AddSubMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)1792 void MacroAssembler::AddSubMacro(const Register& rd,
1793                                  const Register& rn,
1794                                  const Operand& operand,
1795                                  FlagsUpdate S,
1796                                  AddSubOp op) {
1797   // Worst case is add/sub immediate:
1798   //  * up to 4 instructions to materialise the constant
1799   //  * 1 instruction for add/sub
1800   MacroEmissionCheckScope guard(this);
1801 
1802   if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1803       (S == LeaveFlags)) {
1804     // The instruction would be a nop. Avoid generating useless code.
1805     return;
1806   }
1807 
1808   if ((operand.IsImmediate() && !IsImmAddSub(operand.GetImmediate())) ||
1809       (rn.IsZero() && !operand.IsShiftedRegister()) ||
1810       (operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {
1811     UseScratchRegisterScope temps(this);
1812     // Use `rd` as a temp, if we can.
1813     temps.Include(rd);
1814     // We read `rn` after evaluating `operand`.
1815     temps.Exclude(rn);
1816     // It doesn't matter if `operand` is in `temps` (e.g. because it alises
1817     // `rd`) because we don't need it after it is evaluated.
1818     Register temp = temps.AcquireSameSizeAs(rn);
1819     if (operand.IsImmediate()) {
1820       PreShiftImmMode mode = kAnyShift;
1821 
1822       // If the destination or source register is the stack pointer, we can
1823       // only pre-shift the immediate right by values supported in the add/sub
1824       // extend encoding.
1825       if (rd.IsSP()) {
1826         // If the destination is SP and flags will be set, we can't pre-shift
1827         // the immediate at all.
1828         mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP;
1829       } else if (rn.IsSP()) {
1830         mode = kLimitShiftForSP;
1831       }
1832 
1833       Operand imm_operand =
1834           MoveImmediateForShiftedOp(temp, operand.GetImmediate(), mode);
1835       AddSub(rd, rn, imm_operand, S, op);
1836     } else {
1837       Mov(temp, operand);
1838       AddSub(rd, rn, temp, S, op);
1839     }
1840   } else {
1841     AddSub(rd, rn, operand, S, op);
1842   }
1843 }
1844 
1845 
Adc(const Register & rd,const Register & rn,const Operand & operand)1846 void MacroAssembler::Adc(const Register& rd,
1847                          const Register& rn,
1848                          const Operand& operand) {
1849   VIXL_ASSERT(allow_macro_instructions_);
1850   AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1851 }
1852 
1853 
Adcs(const Register & rd,const Register & rn,const Operand & operand)1854 void MacroAssembler::Adcs(const Register& rd,
1855                           const Register& rn,
1856                           const Operand& operand) {
1857   VIXL_ASSERT(allow_macro_instructions_);
1858   AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
1859 }
1860 
1861 
Sbc(const Register & rd,const Register & rn,const Operand & operand)1862 void MacroAssembler::Sbc(const Register& rd,
1863                          const Register& rn,
1864                          const Operand& operand) {
1865   VIXL_ASSERT(allow_macro_instructions_);
1866   AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1867 }
1868 
1869 
Sbcs(const Register & rd,const Register & rn,const Operand & operand)1870 void MacroAssembler::Sbcs(const Register& rd,
1871                           const Register& rn,
1872                           const Operand& operand) {
1873   VIXL_ASSERT(allow_macro_instructions_);
1874   AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
1875 }
1876 
1877 
Ngc(const Register & rd,const Operand & operand)1878 void MacroAssembler::Ngc(const Register& rd, const Operand& operand) {
1879   VIXL_ASSERT(allow_macro_instructions_);
1880   Register zr = AppropriateZeroRegFor(rd);
1881   Sbc(rd, zr, operand);
1882 }
1883 
1884 
Ngcs(const Register & rd,const Operand & operand)1885 void MacroAssembler::Ngcs(const Register& rd, const Operand& operand) {
1886   VIXL_ASSERT(allow_macro_instructions_);
1887   Register zr = AppropriateZeroRegFor(rd);
1888   Sbcs(rd, zr, operand);
1889 }
1890 
1891 
AddSubWithCarryMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)1892 void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1893                                           const Register& rn,
1894                                           const Operand& operand,
1895                                           FlagsUpdate S,
1896                                           AddSubWithCarryOp op) {
1897   VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
1898   // Worst case is addc/subc immediate:
1899   //  * up to 4 instructions to materialise the constant
1900   //  * 1 instruction for add/sub
1901   MacroEmissionCheckScope guard(this);
1902   UseScratchRegisterScope temps(this);
1903   // Use `rd` as a temp, if we can.
1904   temps.Include(rd);
1905   // We read `rn` after evaluating `operand`.
1906   temps.Exclude(rn);
1907   // It doesn't matter if `operand` is in `temps` (e.g. because it alises `rd`)
1908   // because we don't need it after it is evaluated.
1909 
1910   if (operand.IsImmediate() ||
1911       (operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {
1912     // Add/sub with carry (immediate or ROR shifted register.)
1913     Register temp = temps.AcquireSameSizeAs(rn);
1914     Mov(temp, operand);
1915     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1916   } else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {
1917     // Add/sub with carry (shifted register).
1918     VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());
1919     VIXL_ASSERT(operand.GetShift() != ROR);
1920     VIXL_ASSERT(
1921         IsUintN(rd.GetSizeInBits() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
1922                 operand.GetShiftAmount()));
1923     Register temp = temps.AcquireSameSizeAs(rn);
1924     EmitShift(temp,
1925               operand.GetRegister(),
1926               operand.GetShift(),
1927               operand.GetShiftAmount());
1928     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1929   } else if (operand.IsExtendedRegister()) {
1930     // Add/sub with carry (extended register).
1931     VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());
1932     // Add/sub extended supports a shift <= 4. We want to support exactly the
1933     // same modes.
1934     VIXL_ASSERT(operand.GetShiftAmount() <= 4);
1935     VIXL_ASSERT(
1936         operand.GetRegister().Is64Bits() ||
1937         ((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));
1938     Register temp = temps.AcquireSameSizeAs(rn);
1939     EmitExtendShift(temp,
1940                     operand.GetRegister(),
1941                     operand.GetExtend(),
1942                     operand.GetShiftAmount());
1943     AddSubWithCarry(rd, rn, Operand(temp), S, op);
1944   } else {
1945     // The addressing mode is directly supported by the instruction.
1946     AddSubWithCarry(rd, rn, operand, S, op);
1947   }
1948 }
1949 
1950 
Rmif(const Register & xn,unsigned shift,StatusFlags flags)1951 void MacroAssembler::Rmif(const Register& xn,
1952                           unsigned shift,
1953                           StatusFlags flags) {
1954   VIXL_ASSERT(allow_macro_instructions_);
1955   SingleEmissionCheckScope guard(this);
1956   rmif(xn, shift, flags);
1957 }
1958 
1959 
Setf8(const Register & wn)1960 void MacroAssembler::Setf8(const Register& wn) {
1961   VIXL_ASSERT(allow_macro_instructions_);
1962   SingleEmissionCheckScope guard(this);
1963   setf8(wn);
1964 }
1965 
1966 
Setf16(const Register & wn)1967 void MacroAssembler::Setf16(const Register& wn) {
1968   VIXL_ASSERT(allow_macro_instructions_);
1969   SingleEmissionCheckScope guard(this);
1970   setf16(wn);
1971 }
1972 
Chkfeat(const Register & xdn)1973 void MacroAssembler::Chkfeat(const Register& xdn) {
1974   VIXL_ASSERT(allow_macro_instructions_);
1975   MacroEmissionCheckScope guard(this);
1976   if (xdn.Is(x16)) {
1977     chkfeat(xdn);
1978   } else {
1979     UseScratchRegisterScope temps(this);
1980     if (temps.TryAcquire(x16)) {
1981       Mov(x16, xdn);
1982       chkfeat(x16);
1983       Mov(xdn, x16);
1984     } else {
1985       VIXL_ABORT();
1986     }
1987   }
1988 }
1989 
1990 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP)                          \
1991   void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
1992     VIXL_ASSERT(allow_macro_instructions_);                            \
1993     LoadStoreMacro(REG, addr, OP);                                     \
1994   }
LS_MACRO_LIST(DEFINE_FUNCTION)1995 LS_MACRO_LIST(DEFINE_FUNCTION)
1996 #undef DEFINE_FUNCTION
1997 
1998 
1999 void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
2000                                     const MemOperand& addr,
2001                                     LoadStoreOp op) {
2002   VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsImmediatePostIndex() ||
2003               addr.IsImmediatePreIndex() || addr.IsRegisterOffset());
2004 
2005   // Worst case is ldr/str pre/post index:
2006   //  * 1 instruction for ldr/str
2007   //  * up to 4 instructions to materialise the constant
2008   //  * 1 instruction to update the base
2009   MacroEmissionCheckScope guard(this);
2010 
2011   int64_t offset = addr.GetOffset();
2012   unsigned access_size = CalcLSDataSize(op);
2013 
2014   // Check if an immediate offset fits in the immediate field of the
2015   // appropriate instruction. If not, emit two instructions to perform
2016   // the operation.
2017   if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
2018       !IsImmLSUnscaled(offset)) {
2019     // Immediate offset that can't be encoded using unsigned or unscaled
2020     // addressing modes.
2021     UseScratchRegisterScope temps(this);
2022     Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());
2023     Mov(temp, addr.GetOffset());
2024     LoadStore(rt, MemOperand(addr.GetBaseRegister(), temp), op);
2025   } else if (addr.IsImmediatePostIndex() && !IsImmLSUnscaled(offset)) {
2026     // Post-index beyond unscaled addressing range.
2027     LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);
2028     Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));
2029   } else if (addr.IsImmediatePreIndex() && !IsImmLSUnscaled(offset)) {
2030     // Pre-index beyond unscaled addressing range.
2031     Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));
2032     LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);
2033   } else {
2034     // Encodable in one load/store instruction.
2035     LoadStore(rt, addr, op);
2036   }
2037 }
2038 
2039 
2040 #define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
2041   void MacroAssembler::FN(const REGTYPE REG,        \
2042                           const REGTYPE REG2,       \
2043                           const MemOperand& addr) { \
2044     VIXL_ASSERT(allow_macro_instructions_);         \
2045     LoadStorePairMacro(REG, REG2, addr, OP);        \
2046   }
LSPAIR_MACRO_LIST(DEFINE_FUNCTION)2047 LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
2048 #undef DEFINE_FUNCTION
2049 
2050 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
2051                                         const CPURegister& rt2,
2052                                         const MemOperand& addr,
2053                                         LoadStorePairOp op) {
2054   // TODO(all): Should we support register offset for load-store-pair?
2055   VIXL_ASSERT(!addr.IsRegisterOffset());
2056   // Worst case is ldp/stp immediate:
2057   //  * 1 instruction for ldp/stp
2058   //  * up to 4 instructions to materialise the constant
2059   //  * 1 instruction to update the base
2060   MacroEmissionCheckScope guard(this);
2061 
2062   int64_t offset = addr.GetOffset();
2063   unsigned access_size = CalcLSPairDataSize(op);
2064 
2065   // Check if the offset fits in the immediate field of the appropriate
2066   // instruction. If not, emit two instructions to perform the operation.
2067   if (IsImmLSPair(offset, access_size)) {
2068     // Encodable in one load/store pair instruction.
2069     LoadStorePair(rt, rt2, addr, op);
2070   } else {
2071     Register base = addr.GetBaseRegister();
2072     if (addr.IsImmediateOffset()) {
2073       UseScratchRegisterScope temps(this);
2074       Register temp = temps.AcquireSameSizeAs(base);
2075       Add(temp, base, offset);
2076       LoadStorePair(rt, rt2, MemOperand(temp), op);
2077     } else if (addr.IsImmediatePostIndex()) {
2078       LoadStorePair(rt, rt2, MemOperand(base), op);
2079       Add(base, base, offset);
2080     } else {
2081       VIXL_ASSERT(addr.IsImmediatePreIndex());
2082       Add(base, base, offset);
2083       LoadStorePair(rt, rt2, MemOperand(base), op);
2084     }
2085   }
2086 }
2087 
2088 
Prfm(PrefetchOperation op,const MemOperand & addr)2089 void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
2090   MacroEmissionCheckScope guard(this);
2091 
2092   // There are no pre- or post-index modes for prfm.
2093   VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
2094 
2095   // The access size is implicitly 8 bytes for all prefetch operations.
2096   unsigned size = kXRegSizeInBytesLog2;
2097 
2098   // Check if an immediate offset fits in the immediate field of the
2099   // appropriate instruction. If not, emit two instructions to perform
2100   // the operation.
2101   if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.GetOffset(), size) &&
2102       !IsImmLSUnscaled(addr.GetOffset())) {
2103     // Immediate offset that can't be encoded using unsigned or unscaled
2104     // addressing modes.
2105     UseScratchRegisterScope temps(this);
2106     Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());
2107     Mov(temp, addr.GetOffset());
2108     Prefetch(op, MemOperand(addr.GetBaseRegister(), temp));
2109   } else {
2110     // Simple register-offsets are encodable in one instruction.
2111     Prefetch(op, addr);
2112   }
2113 }
2114 
2115 
Push(const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)2116 void MacroAssembler::Push(const CPURegister& src0,
2117                           const CPURegister& src1,
2118                           const CPURegister& src2,
2119                           const CPURegister& src3) {
2120   VIXL_ASSERT(allow_macro_instructions_);
2121   VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
2122   VIXL_ASSERT(src0.IsValid());
2123 
2124   int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
2125   int size = src0.GetSizeInBytes();
2126 
2127   PrepareForPush(count, size);
2128   PushHelper(count, size, src0, src1, src2, src3);
2129 }
2130 
2131 
Pop(const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)2132 void MacroAssembler::Pop(const CPURegister& dst0,
2133                          const CPURegister& dst1,
2134                          const CPURegister& dst2,
2135                          const CPURegister& dst3) {
2136   // It is not valid to pop into the same register more than once in one
2137   // instruction, not even into the zero register.
2138   VIXL_ASSERT(allow_macro_instructions_);
2139   VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
2140   VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
2141   VIXL_ASSERT(dst0.IsValid());
2142 
2143   int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
2144   int size = dst0.GetSizeInBytes();
2145 
2146   PrepareForPop(count, size);
2147   PopHelper(count, size, dst0, dst1, dst2, dst3);
2148 }
2149 
2150 
PushCPURegList(CPURegList registers)2151 void MacroAssembler::PushCPURegList(CPURegList registers) {
2152   VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));
2153   VIXL_ASSERT(!registers.Overlaps(*GetScratchVRegisterList()));
2154   VIXL_ASSERT(allow_macro_instructions_);
2155 
2156   int reg_size = registers.GetRegisterSizeInBytes();
2157   PrepareForPush(registers.GetCount(), reg_size);
2158 
2159   // Bump the stack pointer and store two registers at the bottom.
2160   int size = registers.GetTotalSizeInBytes();
2161   const CPURegister& bottom_0 = registers.PopLowestIndex();
2162   const CPURegister& bottom_1 = registers.PopLowestIndex();
2163   if (bottom_0.IsValid() && bottom_1.IsValid()) {
2164     Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
2165   } else if (bottom_0.IsValid()) {
2166     Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
2167   }
2168 
2169   int offset = 2 * reg_size;
2170   while (!registers.IsEmpty()) {
2171     const CPURegister& src0 = registers.PopLowestIndex();
2172     const CPURegister& src1 = registers.PopLowestIndex();
2173     if (src1.IsValid()) {
2174       Stp(src0, src1, MemOperand(StackPointer(), offset));
2175     } else {
2176       Str(src0, MemOperand(StackPointer(), offset));
2177     }
2178     offset += 2 * reg_size;
2179   }
2180 }
2181 
2182 
PopCPURegList(CPURegList registers)2183 void MacroAssembler::PopCPURegList(CPURegList registers) {
2184   VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));
2185   VIXL_ASSERT(!registers.Overlaps(*GetScratchVRegisterList()));
2186   VIXL_ASSERT(allow_macro_instructions_);
2187 
2188   int reg_size = registers.GetRegisterSizeInBytes();
2189   PrepareForPop(registers.GetCount(), reg_size);
2190 
2191 
2192   int size = registers.GetTotalSizeInBytes();
2193   const CPURegister& bottom_0 = registers.PopLowestIndex();
2194   const CPURegister& bottom_1 = registers.PopLowestIndex();
2195 
2196   int offset = 2 * reg_size;
2197   while (!registers.IsEmpty()) {
2198     const CPURegister& dst0 = registers.PopLowestIndex();
2199     const CPURegister& dst1 = registers.PopLowestIndex();
2200     if (dst1.IsValid()) {
2201       Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
2202     } else {
2203       Ldr(dst0, MemOperand(StackPointer(), offset));
2204     }
2205     offset += 2 * reg_size;
2206   }
2207 
2208   // Load the two registers at the bottom and drop the stack pointer.
2209   if (bottom_0.IsValid() && bottom_1.IsValid()) {
2210     Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
2211   } else if (bottom_0.IsValid()) {
2212     Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
2213   }
2214 }
2215 
2216 
PushMultipleTimes(int count,Register src)2217 void MacroAssembler::PushMultipleTimes(int count, Register src) {
2218   VIXL_ASSERT(allow_macro_instructions_);
2219   int size = src.GetSizeInBytes();
2220 
2221   PrepareForPush(count, size);
2222   // Push up to four registers at a time if possible because if the current
2223   // stack pointer is sp and the register size is 32, registers must be pushed
2224   // in blocks of four in order to maintain the 16-byte alignment for sp.
2225   while (count >= 4) {
2226     PushHelper(4, size, src, src, src, src);
2227     count -= 4;
2228   }
2229   if (count >= 2) {
2230     PushHelper(2, size, src, src, NoReg, NoReg);
2231     count -= 2;
2232   }
2233   if (count == 1) {
2234     PushHelper(1, size, src, NoReg, NoReg, NoReg);
2235     count -= 1;
2236   }
2237   VIXL_ASSERT(count == 0);
2238 }
2239 
2240 
PushHelper(int count,int size,const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)2241 void MacroAssembler::PushHelper(int count,
2242                                 int size,
2243                                 const CPURegister& src0,
2244                                 const CPURegister& src1,
2245                                 const CPURegister& src2,
2246                                 const CPURegister& src3) {
2247   // Ensure that we don't unintentionally modify scratch or debug registers.
2248   // Worst case for size is 2 stp.
2249   ExactAssemblyScope scope(this,
2250                            2 * kInstructionSize,
2251                            ExactAssemblyScope::kMaximumSize);
2252 
2253   VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
2254   VIXL_ASSERT(size == src0.GetSizeInBytes());
2255 
2256   // When pushing multiple registers, the store order is chosen such that
2257   // Push(a, b) is equivalent to Push(a) followed by Push(b).
2258   switch (count) {
2259     case 1:
2260       VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
2261       str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
2262       break;
2263     case 2:
2264       VIXL_ASSERT(src2.IsNone() && src3.IsNone());
2265       stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
2266       break;
2267     case 3:
2268       VIXL_ASSERT(src3.IsNone());
2269       stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
2270       str(src0, MemOperand(StackPointer(), 2 * size));
2271       break;
2272     case 4:
2273       // Skip over 4 * size, then fill in the gap. This allows four W registers
2274       // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
2275       // all times.
2276       stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
2277       stp(src1, src0, MemOperand(StackPointer(), 2 * size));
2278       break;
2279     default:
2280       VIXL_UNREACHABLE();
2281   }
2282 }
2283 
2284 
PopHelper(int count,int size,const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)2285 void MacroAssembler::PopHelper(int count,
2286                                int size,
2287                                const CPURegister& dst0,
2288                                const CPURegister& dst1,
2289                                const CPURegister& dst2,
2290                                const CPURegister& dst3) {
2291   // Ensure that we don't unintentionally modify scratch or debug registers.
2292   // Worst case for size is 2 ldp.
2293   ExactAssemblyScope scope(this,
2294                            2 * kInstructionSize,
2295                            ExactAssemblyScope::kMaximumSize);
2296 
2297   VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
2298   VIXL_ASSERT(size == dst0.GetSizeInBytes());
2299 
2300   // When popping multiple registers, the load order is chosen such that
2301   // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
2302   switch (count) {
2303     case 1:
2304       VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
2305       ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
2306       break;
2307     case 2:
2308       VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
2309       ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
2310       break;
2311     case 3:
2312       VIXL_ASSERT(dst3.IsNone());
2313       ldr(dst2, MemOperand(StackPointer(), 2 * size));
2314       ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
2315       break;
2316     case 4:
2317       // Load the higher addresses first, then load the lower addresses and skip
2318       // the whole block in the second instruction. This allows four W registers
2319       // to be popped using sp, whilst maintaining 16-byte alignment for sp at
2320       // all times.
2321       ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
2322       ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
2323       break;
2324     default:
2325       VIXL_UNREACHABLE();
2326   }
2327 }
2328 
2329 
PrepareForPush(int count,int size)2330 void MacroAssembler::PrepareForPush(int count, int size) {
2331   if (sp.Is(StackPointer())) {
2332     // If the current stack pointer is sp, then it must be aligned to 16 bytes
2333     // on entry and the total size of the specified registers must also be a
2334     // multiple of 16 bytes.
2335     VIXL_ASSERT((count * size) % 16 == 0);
2336   } else {
2337     // Even if the current stack pointer is not the system stack pointer (sp),
2338     // the system stack pointer will still be modified in order to comply with
2339     // ABI rules about accessing memory below the system stack pointer.
2340     BumpSystemStackPointer(count * size);
2341   }
2342 }
2343 
2344 
PrepareForPop(int count,int size)2345 void MacroAssembler::PrepareForPop(int count, int size) {
2346   USE(count, size);
2347   if (sp.Is(StackPointer())) {
2348     // If the current stack pointer is sp, then it must be aligned to 16 bytes
2349     // on entry and the total size of the specified registers must also be a
2350     // multiple of 16 bytes.
2351     VIXL_ASSERT((count * size) % 16 == 0);
2352   }
2353 }
2354 
Poke(const Register & src,const Operand & offset)2355 void MacroAssembler::Poke(const Register& src, const Operand& offset) {
2356   VIXL_ASSERT(allow_macro_instructions_);
2357   if (offset.IsImmediate()) {
2358     VIXL_ASSERT(offset.GetImmediate() >= 0);
2359   }
2360 
2361   Str(src, MemOperand(StackPointer(), offset));
2362 }
2363 
2364 
Peek(const Register & dst,const Operand & offset)2365 void MacroAssembler::Peek(const Register& dst, const Operand& offset) {
2366   VIXL_ASSERT(allow_macro_instructions_);
2367   if (offset.IsImmediate()) {
2368     VIXL_ASSERT(offset.GetImmediate() >= 0);
2369   }
2370 
2371   Ldr(dst, MemOperand(StackPointer(), offset));
2372 }
2373 
2374 
Claim(const Operand & size)2375 void MacroAssembler::Claim(const Operand& size) {
2376   VIXL_ASSERT(allow_macro_instructions_);
2377 
2378   if (size.IsZero()) {
2379     return;
2380   }
2381 
2382   if (size.IsImmediate()) {
2383     VIXL_ASSERT(size.GetImmediate() > 0);
2384     if (sp.Is(StackPointer())) {
2385       VIXL_ASSERT((size.GetImmediate() % 16) == 0);
2386     }
2387   }
2388 
2389   if (!sp.Is(StackPointer())) {
2390     BumpSystemStackPointer(size);
2391   }
2392 
2393   Sub(StackPointer(), StackPointer(), size);
2394 }
2395 
2396 
Drop(const Operand & size)2397 void MacroAssembler::Drop(const Operand& size) {
2398   VIXL_ASSERT(allow_macro_instructions_);
2399 
2400   if (size.IsZero()) {
2401     return;
2402   }
2403 
2404   if (size.IsImmediate()) {
2405     VIXL_ASSERT(size.GetImmediate() > 0);
2406     if (sp.Is(StackPointer())) {
2407       VIXL_ASSERT((size.GetImmediate() % 16) == 0);
2408     }
2409   }
2410 
2411   Add(StackPointer(), StackPointer(), size);
2412 }
2413 
2414 
PushCalleeSavedRegisters()2415 void MacroAssembler::PushCalleeSavedRegisters() {
2416   // Ensure that the macro-assembler doesn't use any scratch registers.
2417   // 10 stp will be emitted.
2418   // TODO(all): Should we use GetCalleeSaved and SavedFP.
2419   ExactAssemblyScope scope(this, 10 * kInstructionSize);
2420 
2421   // This method must not be called unless the current stack pointer is sp.
2422   VIXL_ASSERT(sp.Is(StackPointer()));
2423 
2424   MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);
2425 
2426   stp(x29, x30, tos);
2427   stp(x27, x28, tos);
2428   stp(x25, x26, tos);
2429   stp(x23, x24, tos);
2430   stp(x21, x22, tos);
2431   stp(x19, x20, tos);
2432 
2433   stp(d14, d15, tos);
2434   stp(d12, d13, tos);
2435   stp(d10, d11, tos);
2436   stp(d8, d9, tos);
2437 }
2438 
2439 
PopCalleeSavedRegisters()2440 void MacroAssembler::PopCalleeSavedRegisters() {
2441   // Ensure that the macro-assembler doesn't use any scratch registers.
2442   // 10 ldp will be emitted.
2443   // TODO(all): Should we use GetCalleeSaved and SavedFP.
2444   ExactAssemblyScope scope(this, 10 * kInstructionSize);
2445 
2446   // This method must not be called unless the current stack pointer is sp.
2447   VIXL_ASSERT(sp.Is(StackPointer()));
2448 
2449   MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
2450 
2451   ldp(d8, d9, tos);
2452   ldp(d10, d11, tos);
2453   ldp(d12, d13, tos);
2454   ldp(d14, d15, tos);
2455 
2456   ldp(x19, x20, tos);
2457   ldp(x21, x22, tos);
2458   ldp(x23, x24, tos);
2459   ldp(x25, x26, tos);
2460   ldp(x27, x28, tos);
2461   ldp(x29, x30, tos);
2462 }
2463 
LoadCPURegList(CPURegList registers,const MemOperand & src)2464 void MacroAssembler::LoadCPURegList(CPURegList registers,
2465                                     const MemOperand& src) {
2466   LoadStoreCPURegListHelper(kLoad, registers, src);
2467 }
2468 
StoreCPURegList(CPURegList registers,const MemOperand & dst)2469 void MacroAssembler::StoreCPURegList(CPURegList registers,
2470                                      const MemOperand& dst) {
2471   LoadStoreCPURegListHelper(kStore, registers, dst);
2472 }
2473 
2474 
LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,CPURegList registers,const MemOperand & mem)2475 void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
2476                                                CPURegList registers,
2477                                                const MemOperand& mem) {
2478   // We do not handle pre-indexing or post-indexing.
2479   VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
2480   VIXL_ASSERT(!registers.Overlaps(tmp_list_));
2481   VIXL_ASSERT(!registers.Overlaps(v_tmp_list_));
2482   VIXL_ASSERT(!registers.Overlaps(p_tmp_list_));
2483   VIXL_ASSERT(!registers.IncludesAliasOf(sp));
2484 
2485   UseScratchRegisterScope temps(this);
2486 
2487   MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers, mem, &temps);
2488   const int reg_size = registers.GetRegisterSizeInBytes();
2489 
2490   VIXL_ASSERT(IsPowerOf2(reg_size));
2491 
2492   // Since we are operating on register pairs, we would like to align on double
2493   // the standard size; on the other hand, we don't want to insert an extra
2494   // operation, which will happen if the number of registers is even. Note that
2495   // the alignment of the base pointer is unknown here, but we assume that it
2496   // is more likely to be aligned.
2497   if (((loc.GetOffset() & (2 * reg_size - 1)) != 0) &&
2498       ((registers.GetCount() % 2) != 0)) {
2499     if (op == kStore) {
2500       Str(registers.PopLowestIndex(), loc);
2501     } else {
2502       VIXL_ASSERT(op == kLoad);
2503       Ldr(registers.PopLowestIndex(), loc);
2504     }
2505     loc.AddOffset(reg_size);
2506   }
2507   while (registers.GetCount() >= 2) {
2508     const CPURegister& dst0 = registers.PopLowestIndex();
2509     const CPURegister& dst1 = registers.PopLowestIndex();
2510     if (op == kStore) {
2511       Stp(dst0, dst1, loc);
2512     } else {
2513       VIXL_ASSERT(op == kLoad);
2514       Ldp(dst0, dst1, loc);
2515     }
2516     loc.AddOffset(2 * reg_size);
2517   }
2518   if (!registers.IsEmpty()) {
2519     if (op == kStore) {
2520       Str(registers.PopLowestIndex(), loc);
2521     } else {
2522       VIXL_ASSERT(op == kLoad);
2523       Ldr(registers.PopLowestIndex(), loc);
2524     }
2525   }
2526 }
2527 
BaseMemOperandForLoadStoreCPURegList(const CPURegList & registers,const MemOperand & mem,UseScratchRegisterScope * scratch_scope)2528 MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
2529     const CPURegList& registers,
2530     const MemOperand& mem,
2531     UseScratchRegisterScope* scratch_scope) {
2532   // If necessary, pre-compute the base address for the accesses.
2533   if (mem.IsRegisterOffset()) {
2534     Register reg_base = scratch_scope->AcquireX();
2535     ComputeAddress(reg_base, mem);
2536     return MemOperand(reg_base);
2537 
2538   } else if (mem.IsImmediateOffset()) {
2539     int reg_size = registers.GetRegisterSizeInBytes();
2540     int total_size = registers.GetTotalSizeInBytes();
2541     int64_t min_offset = mem.GetOffset();
2542     int64_t max_offset =
2543         mem.GetOffset() + std::max(0, total_size - 2 * reg_size);
2544     if ((registers.GetCount() >= 2) &&
2545         (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
2546          !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
2547       Register reg_base = scratch_scope->AcquireX();
2548       ComputeAddress(reg_base, mem);
2549       return MemOperand(reg_base);
2550     }
2551   }
2552 
2553   return mem;
2554 }
2555 
BumpSystemStackPointer(const Operand & space)2556 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
2557   VIXL_ASSERT(!sp.Is(StackPointer()));
2558   // TODO: Several callers rely on this not using scratch registers, so we use
2559   // the assembler directly here. However, this means that large immediate
2560   // values of 'space' cannot be handled.
2561   ExactAssemblyScope scope(this, kInstructionSize);
2562   sub(sp, StackPointer(), space);
2563 }
2564 
2565 
2566 // TODO(all): Fix printf for NEON and SVE registers.
2567 
2568 // This is the main Printf implementation. All callee-saved registers are
2569 // 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)2570 void MacroAssembler::PrintfNoPreserve(const char* format,
2571                                       const CPURegister& arg0,
2572                                       const CPURegister& arg1,
2573                                       const CPURegister& arg2,
2574                                       const CPURegister& arg3) {
2575   // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2576   // in most cases anyway, so this restriction shouldn't be too serious.
2577   VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
2578 
2579   // The provided arguments, and their proper PCS registers.
2580   CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
2581   CPURegister pcs[kPrintfMaxArgCount];
2582 
2583   int arg_count = kPrintfMaxArgCount;
2584 
2585   // The PCS varargs registers for printf. Note that x0 is used for the printf
2586   // format string.
2587   static const CPURegList kPCSVarargs =
2588       CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
2589   static const CPURegList kPCSVarargsV =
2590       CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
2591 
2592   // We can use caller-saved registers as scratch values, except for the
2593   // arguments and the PCS registers where they might need to go.
2594   UseScratchRegisterScope temps(this);
2595   temps.Include(kCallerSaved);
2596   temps.Include(kCallerSavedV);
2597   temps.Exclude(kPCSVarargs);
2598   temps.Exclude(kPCSVarargsV);
2599   temps.Exclude(arg0, arg1, arg2, arg3);
2600 
2601   // Copies of the arg lists that we can iterate through.
2602   CPURegList pcs_varargs = kPCSVarargs;
2603   CPURegList pcs_varargs_fp = kPCSVarargsV;
2604 
2605   // Place the arguments. There are lots of clever tricks and optimizations we
2606   // could use here, but Printf is a debug tool so instead we just try to keep
2607   // it simple: Move each input that isn't already in the right place to a
2608   // scratch register, then move everything back.
2609   for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
2610     // Work out the proper PCS register for this argument.
2611     if (args[i].IsRegister()) {
2612       pcs[i] = pcs_varargs.PopLowestIndex().X();
2613       // We might only need a W register here. We need to know the size of the
2614       // argument so we can properly encode it for the simulator call.
2615       if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
2616     } else if (args[i].IsVRegister()) {
2617       // In C, floats are always cast to doubles for varargs calls.
2618       pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
2619     } else {
2620       VIXL_ASSERT(args[i].IsNone());
2621       arg_count = i;
2622       break;
2623     }
2624 
2625     // If the argument is already in the right place, leave it where it is.
2626     if (args[i].Aliases(pcs[i])) continue;
2627 
2628     // Otherwise, if the argument is in a PCS argument register, allocate an
2629     // appropriate scratch register and then move it out of the way.
2630     if (kPCSVarargs.IncludesAliasOf(args[i]) ||
2631         kPCSVarargsV.IncludesAliasOf(args[i])) {
2632       if (args[i].IsRegister()) {
2633         Register old_arg = Register(args[i]);
2634         Register new_arg = temps.AcquireSameSizeAs(old_arg);
2635         Mov(new_arg, old_arg);
2636         args[i] = new_arg;
2637       } else {
2638         VRegister old_arg(args[i]);
2639         VRegister new_arg = temps.AcquireSameSizeAs(old_arg);
2640         Fmov(new_arg, old_arg);
2641         args[i] = new_arg;
2642       }
2643     }
2644   }
2645 
2646   // Do a second pass to move values into their final positions and perform any
2647   // conversions that may be required.
2648   for (int i = 0; i < arg_count; i++) {
2649     VIXL_ASSERT(pcs[i].GetType() == args[i].GetType());
2650     if (pcs[i].IsRegister()) {
2651       Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2652     } else {
2653       VIXL_ASSERT(pcs[i].IsVRegister());
2654       if (pcs[i].GetSizeInBits() == args[i].GetSizeInBits()) {
2655         Fmov(VRegister(pcs[i]), VRegister(args[i]));
2656       } else {
2657         Fcvt(VRegister(pcs[i]), VRegister(args[i]));
2658       }
2659     }
2660   }
2661 
2662   // Load the format string into x0, as per the procedure-call standard.
2663   //
2664   // To make the code as portable as possible, the format string is encoded
2665   // directly in the instruction stream. It might be cleaner to encode it in a
2666   // literal pool, but since Printf is usually used for debugging, it is
2667   // beneficial for it to be minimally dependent on other features.
2668   temps.Exclude(x0);
2669   Label format_address;
2670   Adr(x0, &format_address);
2671 
2672   // Emit the format string directly in the instruction stream.
2673   {
2674     BlockPoolsScope scope(this);
2675     // Data emitted:
2676     //   branch
2677     //   strlen(format) + 1 (includes null termination)
2678     //   padding to next instruction
2679     //   unreachable
2680     EmissionCheckScope guard(this,
2681                              AlignUp(strlen(format) + 1, kInstructionSize) +
2682                                  2 * kInstructionSize);
2683     Label after_data;
2684     B(&after_data);
2685     Bind(&format_address);
2686     EmitString(format);
2687     Unreachable();
2688     Bind(&after_data);
2689   }
2690 
2691   // We don't pass any arguments on the stack, but we still need to align the C
2692   // stack pointer to a 16-byte boundary for PCS compliance.
2693   if (!sp.Is(StackPointer())) {
2694     Bic(sp, StackPointer(), 0xf);
2695   }
2696 
2697   // Actually call printf. This part needs special handling for the simulator,
2698   // since the system printf function will use a different instruction set and
2699   // the procedure-call standard will not be compatible.
2700   if (generate_simulator_code_) {
2701     ExactAssemblyScope scope(this, kPrintfLength);
2702     hlt(kPrintfOpcode);
2703     dc32(arg_count);  // kPrintfArgCountOffset
2704 
2705     // Determine the argument pattern.
2706     uint32_t arg_pattern_list = 0;
2707     for (int i = 0; i < arg_count; i++) {
2708       uint32_t arg_pattern;
2709       if (pcs[i].IsRegister()) {
2710         arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
2711       } else {
2712         VIXL_ASSERT(pcs[i].Is64Bits());
2713         arg_pattern = kPrintfArgD;
2714       }
2715       VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
2716       arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
2717     }
2718     dc32(arg_pattern_list);  // kPrintfArgPatternListOffset
2719   } else {
2720     Register tmp = temps.AcquireX();
2721     Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2722     Blr(tmp);
2723   }
2724 }
2725 
2726 
Printf(const char * format,CPURegister arg0,CPURegister arg1,CPURegister arg2,CPURegister arg3)2727 void MacroAssembler::Printf(const char* format,
2728                             CPURegister arg0,
2729                             CPURegister arg1,
2730                             CPURegister arg2,
2731                             CPURegister arg3) {
2732   // We can only print sp if it is the current stack pointer.
2733   if (!sp.Is(StackPointer())) {
2734     VIXL_ASSERT(!sp.Aliases(arg0));
2735     VIXL_ASSERT(!sp.Aliases(arg1));
2736     VIXL_ASSERT(!sp.Aliases(arg2));
2737     VIXL_ASSERT(!sp.Aliases(arg3));
2738   }
2739 
2740   // Make sure that the macro assembler doesn't try to use any of our arguments
2741   // as scratch registers.
2742   UseScratchRegisterScope exclude_all(this);
2743   exclude_all.ExcludeAll();
2744 
2745   // Preserve all caller-saved registers as well as NZCV.
2746   // If sp is the stack pointer, PushCPURegList asserts that the size of each
2747   // list is a multiple of 16 bytes.
2748   PushCPURegList(kCallerSaved);
2749   PushCPURegList(kCallerSavedV);
2750 
2751   {
2752     UseScratchRegisterScope temps(this);
2753     // We can use caller-saved registers as scratch values (except for argN).
2754     temps.Include(kCallerSaved);
2755     temps.Include(kCallerSavedV);
2756     temps.Exclude(arg0, arg1, arg2, arg3);
2757 
2758     // If any of the arguments are the current stack pointer, allocate a new
2759     // register for them, and adjust the value to compensate for pushing the
2760     // caller-saved registers.
2761     bool arg0_sp = StackPointer().Aliases(arg0);
2762     bool arg1_sp = StackPointer().Aliases(arg1);
2763     bool arg2_sp = StackPointer().Aliases(arg2);
2764     bool arg3_sp = StackPointer().Aliases(arg3);
2765     if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
2766       // Allocate a register to hold the original stack pointer value, to pass
2767       // to PrintfNoPreserve as an argument.
2768       Register arg_sp = temps.AcquireX();
2769       Add(arg_sp,
2770           StackPointer(),
2771           kCallerSaved.GetTotalSizeInBytes() +
2772               kCallerSavedV.GetTotalSizeInBytes());
2773       if (arg0_sp) arg0 = Register(arg_sp.GetCode(), arg0.GetSizeInBits());
2774       if (arg1_sp) arg1 = Register(arg_sp.GetCode(), arg1.GetSizeInBits());
2775       if (arg2_sp) arg2 = Register(arg_sp.GetCode(), arg2.GetSizeInBits());
2776       if (arg3_sp) arg3 = Register(arg_sp.GetCode(), arg3.GetSizeInBits());
2777     }
2778 
2779     // Preserve NZCV.
2780     Register tmp = temps.AcquireX();
2781     Mrs(tmp, NZCV);
2782     Push(tmp, xzr);
2783     temps.Release(tmp);
2784 
2785     PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2786 
2787     // Restore NZCV.
2788     tmp = temps.AcquireX();
2789     Pop(xzr, tmp);
2790     Msr(NZCV, tmp);
2791     temps.Release(tmp);
2792   }
2793 
2794   PopCPURegList(kCallerSavedV);
2795   PopCPURegList(kCallerSaved);
2796 }
2797 
Trace(TraceParameters parameters,TraceCommand command)2798 void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
2799   VIXL_ASSERT(allow_macro_instructions_);
2800 
2801   if (generate_simulator_code_) {
2802     // The arguments to the trace pseudo instruction need to be contiguous in
2803     // memory, so make sure we don't try to emit a literal pool.
2804     ExactAssemblyScope scope(this, kTraceLength);
2805 
2806     Label start;
2807     bind(&start);
2808 
2809     // Refer to simulator-aarch64.h for a description of the marker and its
2810     // arguments.
2811     hlt(kTraceOpcode);
2812 
2813     VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2814     dc32(parameters);
2815 
2816     VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2817     dc32(command);
2818   } else {
2819     // Emit nothing on real hardware.
2820     USE(parameters, command);
2821   }
2822 }
2823 
2824 
Log(TraceParameters parameters)2825 void MacroAssembler::Log(TraceParameters parameters) {
2826   VIXL_ASSERT(allow_macro_instructions_);
2827 
2828   if (generate_simulator_code_) {
2829     // The arguments to the log pseudo instruction need to be contiguous in
2830     // memory, so make sure we don't try to emit a literal pool.
2831     ExactAssemblyScope scope(this, kLogLength);
2832 
2833     Label start;
2834     bind(&start);
2835 
2836     // Refer to simulator-aarch64.h for a description of the marker and its
2837     // arguments.
2838     hlt(kLogOpcode);
2839 
2840     VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2841     dc32(parameters);
2842   } else {
2843     // Emit nothing on real hardware.
2844     USE(parameters);
2845   }
2846 }
2847 
2848 
SetSimulatorCPUFeatures(const CPUFeatures & features)2849 void MacroAssembler::SetSimulatorCPUFeatures(const CPUFeatures& features) {
2850   ConfigureSimulatorCPUFeaturesHelper(features, kSetCPUFeaturesOpcode);
2851 }
2852 
2853 
EnableSimulatorCPUFeatures(const CPUFeatures & features)2854 void MacroAssembler::EnableSimulatorCPUFeatures(const CPUFeatures& features) {
2855   ConfigureSimulatorCPUFeaturesHelper(features, kEnableCPUFeaturesOpcode);
2856 }
2857 
2858 
DisableSimulatorCPUFeatures(const CPUFeatures & features)2859 void MacroAssembler::DisableSimulatorCPUFeatures(const CPUFeatures& features) {
2860   ConfigureSimulatorCPUFeaturesHelper(features, kDisableCPUFeaturesOpcode);
2861 }
2862 
2863 
ConfigureSimulatorCPUFeaturesHelper(const CPUFeatures & features,DebugHltOpcode action)2864 void MacroAssembler::ConfigureSimulatorCPUFeaturesHelper(
2865     const CPUFeatures& features, DebugHltOpcode action) {
2866   VIXL_ASSERT(allow_macro_instructions_);
2867   VIXL_ASSERT(generate_simulator_code_);
2868 
2869   typedef ConfigureCPUFeaturesElementType ElementType;
2870   VIXL_ASSERT(CPUFeatures::kNumberOfFeatures <=
2871               std::numeric_limits<ElementType>::max());
2872 
2873   size_t count = features.Count();
2874 
2875   size_t preamble_length = kConfigureCPUFeaturesListOffset;
2876   size_t list_length = (count + 1) * sizeof(ElementType);
2877   size_t padding_length = AlignUp(list_length, kInstructionSize) - list_length;
2878 
2879   size_t total_length = preamble_length + list_length + padding_length;
2880 
2881   // Check the overall code size as well as the size of each component.
2882   ExactAssemblyScope guard_total(this, total_length);
2883 
2884   {  // Preamble: the opcode itself.
2885     ExactAssemblyScope guard_preamble(this, preamble_length);
2886     hlt(action);
2887   }
2888   {  // A kNone-terminated list of features.
2889     ExactAssemblyScope guard_list(this, list_length);
2890     for (CPUFeatures::const_iterator it = features.begin();
2891          it != features.end();
2892          ++it) {
2893       dc(static_cast<ElementType>(*it));
2894     }
2895     dc(static_cast<ElementType>(CPUFeatures::kNone));
2896   }
2897   {  // Padding for instruction alignment.
2898     ExactAssemblyScope guard_padding(this, padding_length);
2899     for (size_t size = 0; size < padding_length; size += sizeof(ElementType)) {
2900       // The exact value is arbitrary.
2901       dc(static_cast<ElementType>(CPUFeatures::kNone));
2902     }
2903   }
2904 }
2905 
SaveSimulatorCPUFeatures()2906 void MacroAssembler::SaveSimulatorCPUFeatures() {
2907   VIXL_ASSERT(allow_macro_instructions_);
2908   VIXL_ASSERT(generate_simulator_code_);
2909   SingleEmissionCheckScope guard(this);
2910   hlt(kSaveCPUFeaturesOpcode);
2911 }
2912 
2913 
RestoreSimulatorCPUFeatures()2914 void MacroAssembler::RestoreSimulatorCPUFeatures() {
2915   VIXL_ASSERT(allow_macro_instructions_);
2916   VIXL_ASSERT(generate_simulator_code_);
2917   SingleEmissionCheckScope guard(this);
2918   hlt(kRestoreCPUFeaturesOpcode);
2919 }
2920 
2921 
Open(MacroAssembler * masm)2922 void UseScratchRegisterScope::Open(MacroAssembler* masm) {
2923   VIXL_ASSERT(masm_ == NULL);
2924   VIXL_ASSERT(masm != NULL);
2925   masm_ = masm;
2926 
2927   CPURegList* available = masm->GetScratchRegisterList();
2928   CPURegList* available_v = masm->GetScratchVRegisterList();
2929   CPURegList* available_p = masm->GetScratchPRegisterList();
2930   old_available_ = available->GetList();
2931   old_available_v_ = available_v->GetList();
2932   old_available_p_ = available_p->GetList();
2933   VIXL_ASSERT(available->GetType() == CPURegister::kRegister);
2934   VIXL_ASSERT(available_v->GetType() == CPURegister::kVRegister);
2935   VIXL_ASSERT(available_p->GetType() == CPURegister::kPRegister);
2936 
2937   parent_ = masm->GetCurrentScratchRegisterScope();
2938   masm->SetCurrentScratchRegisterScope(this);
2939 }
2940 
2941 
Close()2942 void UseScratchRegisterScope::Close() {
2943   if (masm_ != NULL) {
2944     // Ensure that scopes nest perfectly, and do not outlive their parents.
2945     // This is a run-time check because the order of destruction of objects in
2946     // the _same_ scope is implementation-defined, and is likely to change in
2947     // optimised builds.
2948     VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
2949     masm_->SetCurrentScratchRegisterScope(parent_);
2950 
2951     masm_->GetScratchRegisterList()->SetList(old_available_);
2952     masm_->GetScratchVRegisterList()->SetList(old_available_v_);
2953     masm_->GetScratchPRegisterList()->SetList(old_available_p_);
2954 
2955     masm_ = NULL;
2956   }
2957 }
2958 
2959 
IsAvailable(const CPURegister & reg) const2960 bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2961   return masm_->GetScratchRegisterList()->IncludesAliasOf(reg) ||
2962          masm_->GetScratchVRegisterList()->IncludesAliasOf(reg) ||
2963          masm_->GetScratchPRegisterList()->IncludesAliasOf(reg);
2964 }
2965 
AcquireRegisterOfSize(int size_in_bits)2966 Register UseScratchRegisterScope::AcquireRegisterOfSize(int size_in_bits) {
2967   int code = AcquireFrom(masm_->GetScratchRegisterList()).GetCode();
2968   return Register(code, size_in_bits);
2969 }
2970 
2971 
AcquireVRegisterOfSize(int size_in_bits)2972 VRegister UseScratchRegisterScope::AcquireVRegisterOfSize(int size_in_bits) {
2973   int code = AcquireFrom(masm_->GetScratchVRegisterList()).GetCode();
2974   return VRegister(code, size_in_bits);
2975 }
2976 
2977 
Release(const CPURegister & reg)2978 void UseScratchRegisterScope::Release(const CPURegister& reg) {
2979   VIXL_ASSERT(masm_ != NULL);
2980 
2981   // Release(NoReg) has no effect.
2982   if (reg.IsNone()) return;
2983 
2984   ReleaseByCode(GetAvailableListFor(reg.GetBank()), reg.GetCode());
2985 }
2986 
2987 
Include(const CPURegList & list)2988 void UseScratchRegisterScope::Include(const CPURegList& list) {
2989   VIXL_ASSERT(masm_ != NULL);
2990 
2991   // Including an empty list has no effect.
2992   if (list.IsEmpty()) return;
2993   VIXL_ASSERT(list.GetType() != CPURegister::kNoRegister);
2994 
2995   RegList reg_list = list.GetList();
2996   if (list.GetType() == CPURegister::kRegister) {
2997     // Make sure that neither sp nor xzr are included the list.
2998     reg_list &= ~(xzr.GetBit() | sp.GetBit());
2999   }
3000 
3001   IncludeByRegList(GetAvailableListFor(list.GetBank()), reg_list);
3002 }
3003 
3004 
Include(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)3005 void UseScratchRegisterScope::Include(const Register& reg1,
3006                                       const Register& reg2,
3007                                       const Register& reg3,
3008                                       const Register& reg4) {
3009   VIXL_ASSERT(masm_ != NULL);
3010   RegList include =
3011       reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
3012   // Make sure that neither sp nor xzr are included the list.
3013   include &= ~(xzr.GetBit() | sp.GetBit());
3014 
3015   IncludeByRegList(masm_->GetScratchRegisterList(), include);
3016 }
3017 
3018 
Include(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)3019 void UseScratchRegisterScope::Include(const VRegister& reg1,
3020                                       const VRegister& reg2,
3021                                       const VRegister& reg3,
3022                                       const VRegister& reg4) {
3023   RegList include =
3024       reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
3025   IncludeByRegList(masm_->GetScratchVRegisterList(), include);
3026 }
3027 
3028 
Include(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)3029 void UseScratchRegisterScope::Include(const CPURegister& reg1,
3030                                       const CPURegister& reg2,
3031                                       const CPURegister& reg3,
3032                                       const CPURegister& reg4) {
3033   RegList include = 0;
3034   RegList include_v = 0;
3035   RegList include_p = 0;
3036 
3037   const CPURegister regs[] = {reg1, reg2, reg3, reg4};
3038 
3039   for (size_t i = 0; i < ArrayLength(regs); i++) {
3040     RegList bit = regs[i].GetBit();
3041     switch (regs[i].GetBank()) {
3042       case CPURegister::kNoRegisterBank:
3043         // Include(NoReg) has no effect.
3044         VIXL_ASSERT(regs[i].IsNone());
3045         break;
3046       case CPURegister::kRRegisterBank:
3047         include |= bit;
3048         break;
3049       case CPURegister::kVRegisterBank:
3050         include_v |= bit;
3051         break;
3052       case CPURegister::kPRegisterBank:
3053         include_p |= bit;
3054         break;
3055     }
3056   }
3057 
3058   IncludeByRegList(masm_->GetScratchRegisterList(), include);
3059   IncludeByRegList(masm_->GetScratchVRegisterList(), include_v);
3060   IncludeByRegList(masm_->GetScratchPRegisterList(), include_p);
3061 }
3062 
3063 
Exclude(const CPURegList & list)3064 void UseScratchRegisterScope::Exclude(const CPURegList& list) {
3065   ExcludeByRegList(GetAvailableListFor(list.GetBank()), list.GetList());
3066 }
3067 
3068 
Exclude(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)3069 void UseScratchRegisterScope::Exclude(const Register& reg1,
3070                                       const Register& reg2,
3071                                       const Register& reg3,
3072                                       const Register& reg4) {
3073   RegList exclude =
3074       reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
3075   ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);
3076 }
3077 
3078 
Exclude(const VRegister & reg1,const VRegister & reg2,const VRegister & reg3,const VRegister & reg4)3079 void UseScratchRegisterScope::Exclude(const VRegister& reg1,
3080                                       const VRegister& reg2,
3081                                       const VRegister& reg3,
3082                                       const VRegister& reg4) {
3083   RegList exclude_v =
3084       reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
3085   ExcludeByRegList(masm_->GetScratchVRegisterList(), exclude_v);
3086 }
3087 
3088 
Exclude(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)3089 void UseScratchRegisterScope::Exclude(const CPURegister& reg1,
3090                                       const CPURegister& reg2,
3091                                       const CPURegister& reg3,
3092                                       const CPURegister& reg4) {
3093   RegList exclude = 0;
3094   RegList exclude_v = 0;
3095   RegList exclude_p = 0;
3096 
3097   const CPURegister regs[] = {reg1, reg2, reg3, reg4};
3098 
3099   for (size_t i = 0; i < ArrayLength(regs); i++) {
3100     RegList bit = regs[i].GetBit();
3101     switch (regs[i].GetBank()) {
3102       case CPURegister::kNoRegisterBank:
3103         // Exclude(NoReg) has no effect.
3104         VIXL_ASSERT(regs[i].IsNone());
3105         break;
3106       case CPURegister::kRRegisterBank:
3107         exclude |= bit;
3108         break;
3109       case CPURegister::kVRegisterBank:
3110         exclude_v |= bit;
3111         break;
3112       case CPURegister::kPRegisterBank:
3113         exclude_p |= bit;
3114         break;
3115     }
3116   }
3117 
3118   ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);
3119   ExcludeByRegList(masm_->GetScratchVRegisterList(), exclude_v);
3120   ExcludeByRegList(masm_->GetScratchPRegisterList(), exclude_p);
3121 }
3122 
3123 
ExcludeAll()3124 void UseScratchRegisterScope::ExcludeAll() {
3125   ExcludeByRegList(masm_->GetScratchRegisterList(),
3126                    masm_->GetScratchRegisterList()->GetList());
3127   ExcludeByRegList(masm_->GetScratchVRegisterList(),
3128                    masm_->GetScratchVRegisterList()->GetList());
3129   ExcludeByRegList(masm_->GetScratchPRegisterList(),
3130                    masm_->GetScratchPRegisterList()->GetList());
3131 }
3132 
3133 
AcquireFrom(CPURegList * available,RegList mask)3134 CPURegister UseScratchRegisterScope::AcquireFrom(CPURegList* available,
3135                                                  RegList mask) {
3136   VIXL_CHECK((available->GetList() & mask) != 0);
3137   CPURegister result = available->PopLowestIndex(mask);
3138   VIXL_ASSERT(!AreAliased(result, xzr, sp));
3139   return result;
3140 }
3141 
3142 
ReleaseByCode(CPURegList * available,int code)3143 void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
3144   ReleaseByRegList(available, static_cast<RegList>(1) << code);
3145 }
3146 
3147 
ReleaseByRegList(CPURegList * available,RegList regs)3148 void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
3149                                                RegList regs) {
3150   available->SetList(available->GetList() | regs);
3151 }
3152 
3153 
IncludeByRegList(CPURegList * available,RegList regs)3154 void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
3155                                                RegList regs) {
3156   available->SetList(available->GetList() | regs);
3157 }
3158 
3159 
ExcludeByRegList(CPURegList * available,RegList exclude)3160 void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
3161                                                RegList exclude) {
3162   available->SetList(available->GetList() & ~exclude);
3163 }
3164 
GetAvailableListFor(CPURegister::RegisterBank bank)3165 CPURegList* UseScratchRegisterScope::GetAvailableListFor(
3166     CPURegister::RegisterBank bank) {
3167   switch (bank) {
3168     case CPURegister::kNoRegisterBank:
3169       return NULL;
3170     case CPURegister::kRRegisterBank:
3171       return masm_->GetScratchRegisterList();
3172     case CPURegister::kVRegisterBank:
3173       return masm_->GetScratchVRegisterList();
3174     case CPURegister::kPRegisterBank:
3175       return masm_->GetScratchPRegisterList();
3176   }
3177   VIXL_UNREACHABLE();
3178   return NULL;
3179 }
3180 
3181 }  // namespace aarch64
3182 }  // namespace vixl
3183