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