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