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