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