1 // Copyright 2015, ARM Limited
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 <ctype.h>
28
29 #include "vixl/a64/macro-assembler-a64.h"
30
31 namespace vixl {
32
33
Release()34 void Pool::Release() {
35 if (--monitor_ == 0) {
36 // Ensure the pool has not been blocked for too long.
37 VIXL_ASSERT(masm_->CursorOffset() < checkpoint_);
38 }
39 }
40
41
SetNextCheckpoint(ptrdiff_t checkpoint)42 void Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {
43 masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);
44 checkpoint_ = checkpoint;
45 }
46
47
LiteralPool(MacroAssembler * masm)48 LiteralPool::LiteralPool(MacroAssembler* masm)
49 : Pool(masm), size_(0), first_use_(-1),
50 recommended_checkpoint_(kNoCheckpointRequired) {
51 }
52
53
~LiteralPool()54 LiteralPool::~LiteralPool() {
55 VIXL_ASSERT(IsEmpty());
56 VIXL_ASSERT(!IsBlocked());
57 for (std::vector<RawLiteral*>::iterator it = deleted_on_destruction_.begin();
58 it != deleted_on_destruction_.end();
59 it++) {
60 delete *it;
61 }
62 }
63
64
Reset()65 void LiteralPool::Reset() {
66 std::vector<RawLiteral*>::iterator it, end;
67 for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
68 RawLiteral* literal = *it;
69 if (literal->deletion_policy_ == RawLiteral::kDeletedOnPlacementByPool) {
70 delete literal;
71 }
72 }
73 entries_.clear();
74 size_ = 0;
75 first_use_ = -1;
76 Pool::Reset();
77 recommended_checkpoint_ = kNoCheckpointRequired;
78 }
79
80
CheckEmitFor(size_t amount,EmitOption option)81 void LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {
82 if (IsEmpty() || IsBlocked()) return;
83
84 ptrdiff_t distance = masm_->CursorOffset() + amount - first_use_;
85 if (distance >= kRecommendedLiteralPoolRange) {
86 Emit(option);
87 }
88 }
89
90
Emit(EmitOption option)91 void LiteralPool::Emit(EmitOption option) {
92 // There is an issue if we are asked to emit a blocked or empty pool.
93 VIXL_ASSERT(!IsBlocked());
94 VIXL_ASSERT(!IsEmpty());
95
96 size_t pool_size = Size();
97 size_t emit_size = pool_size;
98 if (option == kBranchRequired) emit_size += kInstructionSize;
99 Label end_of_pool;
100
101 VIXL_ASSERT(emit_size % kInstructionSize == 0);
102 InstructionAccurateScope guard(masm_, emit_size / kInstructionSize);
103 if (option == kBranchRequired) masm_->b(&end_of_pool);
104
105 // Marker indicating the size of the literal pool in 32-bit words.
106 VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);
107 masm_->ldr(xzr, static_cast<int>(pool_size / kWRegSizeInBytes));
108
109 // Now populate the literal pool.
110 std::vector<RawLiteral*>::iterator it, end;
111 for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
112 VIXL_ASSERT((*it)->IsUsed());
113 masm_->place(*it);
114 }
115
116 if (option == kBranchRequired) masm_->bind(&end_of_pool);
117
118 Reset();
119 }
120
121
AddEntry(RawLiteral * literal)122 void LiteralPool::AddEntry(RawLiteral* literal) {
123 // A literal must be registered immediately before its first use. Here we
124 // cannot control that it is its first use, but we check no code has been
125 // emitted since its last use.
126 VIXL_ASSERT(masm_->CursorOffset() == literal->last_use());
127
128 UpdateFirstUse(masm_->CursorOffset());
129 VIXL_ASSERT(masm_->CursorOffset() >= first_use_);
130 entries_.push_back(literal);
131 size_ += literal->size();
132 }
133
134
UpdateFirstUse(ptrdiff_t use_position)135 void LiteralPool::UpdateFirstUse(ptrdiff_t use_position) {
136 first_use_ = std::min(first_use_, use_position);
137 if (first_use_ == -1) {
138 first_use_ = use_position;
139 SetNextRecommendedCheckpoint(NextRecommendedCheckpoint());
140 SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);
141 } else {
142 VIXL_ASSERT(use_position > first_use_);
143 }
144 }
145
146
Reset()147 void VeneerPool::Reset() {
148 Pool::Reset();
149 unresolved_branches_.Reset();
150 }
151
152
Release()153 void VeneerPool::Release() {
154 if (--monitor_ == 0) {
155 VIXL_ASSERT(IsEmpty() ||
156 masm_->CursorOffset() < unresolved_branches_.FirstLimit());
157 }
158 }
159
160
RegisterUnresolvedBranch(ptrdiff_t branch_pos,Label * label,ImmBranchType branch_type)161 void VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,
162 Label* label,
163 ImmBranchType branch_type) {
164 VIXL_ASSERT(!label->IsBound());
165 BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);
166 unresolved_branches_.insert(branch_info);
167 UpdateNextCheckPoint();
168 // TODO: In debug mode register the label with the assembler to make sure it
169 // is bound with masm Bind and not asm bind.
170 }
171
172
DeleteUnresolvedBranchInfoForLabel(Label * label)173 void VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {
174 if (IsEmpty()) {
175 VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);
176 return;
177 }
178
179 if (label->IsLinked()) {
180 Label::LabelLinksIterator links_it(label);
181 for (; !links_it.Done(); links_it.Advance()) {
182 ptrdiff_t link_offset = *links_it.Current();
183 Instruction* link = masm_->InstructionAt(link_offset);
184
185 // ADR instructions are not handled.
186 if (BranchTypeUsesVeneers(link->BranchType())) {
187 BranchInfo branch_info(link_offset, label, link->BranchType());
188 unresolved_branches_.erase(branch_info);
189 }
190 }
191 }
192
193 UpdateNextCheckPoint();
194 }
195
196
ShouldEmitVeneer(int64_t max_reachable_pc,size_t amount)197 bool VeneerPool::ShouldEmitVeneer(int64_t max_reachable_pc, size_t amount) {
198 ptrdiff_t offset =
199 kPoolNonVeneerCodeSize + amount + MaxSize() + OtherPoolsMaxSize();
200 return (masm_->CursorOffset() + offset) > max_reachable_pc;
201 }
202
203
CheckEmitFor(size_t amount,EmitOption option)204 void VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {
205 if (IsEmpty()) return;
206
207 VIXL_ASSERT(masm_->CursorOffset() < unresolved_branches_.FirstLimit());
208
209 if (IsBlocked()) return;
210
211 if (ShouldEmitVeneers(amount)) {
212 Emit(option, amount);
213 } else {
214 UpdateNextCheckPoint();
215 }
216 }
217
218
Emit(EmitOption option,size_t amount)219 void VeneerPool::Emit(EmitOption option, size_t amount) {
220 // There is an issue if we are asked to emit a blocked or empty pool.
221 VIXL_ASSERT(!IsBlocked());
222 VIXL_ASSERT(!IsEmpty());
223
224 Label end;
225 if (option == kBranchRequired) {
226 InstructionAccurateScope scope(masm_, 1);
227 masm_->b(&end);
228 }
229
230 // We want to avoid generating veneer pools too often, so generate veneers for
231 // branches that don't immediately require a veneer but will soon go out of
232 // range.
233 static const size_t kVeneerEmissionMargin = 1 * KBytes;
234
235 for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {
236 BranchInfo* branch_info = it.Current();
237 if (ShouldEmitVeneer(branch_info->max_reachable_pc_,
238 amount + kVeneerEmissionMargin)) {
239 InstructionAccurateScope scope(masm_, kVeneerCodeSize / kInstructionSize);
240 ptrdiff_t branch_pos = branch_info->pc_offset_;
241 Instruction* branch = masm_->InstructionAt(branch_pos);
242 Label* label = branch_info->label_;
243
244 // Patch the branch to point to the current position, and emit a branch
245 // to the label.
246 Instruction* veneer = masm_->GetCursorAddress<Instruction*>();
247 branch->SetImmPCOffsetTarget(veneer);
248 masm_->b(label);
249
250 // Update the label. The branch patched does not point to it any longer.
251 label->DeleteLink(branch_pos);
252
253 it.DeleteCurrentAndAdvance();
254 } else {
255 it.AdvanceToNextType();
256 }
257 }
258
259 UpdateNextCheckPoint();
260
261 masm_->bind(&end);
262 }
263
264
EmissionCheckScope(MacroAssembler * masm,size_t size)265 EmissionCheckScope::EmissionCheckScope(MacroAssembler* masm, size_t size)
266 : masm_(masm) {
267 masm_->EnsureEmitFor(size);
268 masm_->BlockPools();
269 #ifdef VIXL_DEBUG
270 masm_->Bind(&start_);
271 size_ = size;
272 masm_->AcquireBuffer();
273 #endif
274 }
275
276
~EmissionCheckScope()277 EmissionCheckScope::~EmissionCheckScope() {
278 #ifdef VIXL_DEBUG
279 masm_->ReleaseBuffer();
280 VIXL_ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) <= size_);
281 #endif
282 masm_->ReleasePools();
283 }
284
285
MacroAssembler(size_t capacity,PositionIndependentCodeOption pic)286 MacroAssembler::MacroAssembler(size_t capacity,
287 PositionIndependentCodeOption pic)
288 : Assembler(capacity, pic),
289 #ifdef VIXL_DEBUG
290 allow_macro_instructions_(true),
291 #endif
292 allow_simulator_instructions_(VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE),
293 sp_(sp),
294 tmp_list_(ip0, ip1),
295 fptmp_list_(d31),
296 literal_pool_(this),
297 veneer_pool_(this),
298 recommended_checkpoint_(Pool::kNoCheckpointRequired) {
299 checkpoint_ = NextCheckPoint();
300 }
301
302
MacroAssembler(byte * buffer,size_t capacity,PositionIndependentCodeOption pic)303 MacroAssembler::MacroAssembler(byte * buffer,
304 size_t capacity,
305 PositionIndependentCodeOption pic)
306 : Assembler(buffer, capacity, pic),
307 #ifdef VIXL_DEBUG
308 allow_macro_instructions_(true),
309 #endif
310 allow_simulator_instructions_(VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE),
311 sp_(sp),
312 tmp_list_(ip0, ip1),
313 fptmp_list_(d31),
314 literal_pool_(this),
315 veneer_pool_(this),
316 recommended_checkpoint_(Pool::kNoCheckpointRequired) {
317 checkpoint_ = NextCheckPoint();
318 }
319
320
~MacroAssembler()321 MacroAssembler::~MacroAssembler() {
322 }
323
324
Reset()325 void MacroAssembler::Reset() {
326 Assembler::Reset();
327
328 VIXL_ASSERT(!literal_pool_.IsBlocked());
329 literal_pool_.Reset();
330 veneer_pool_.Reset();
331
332 checkpoint_ = NextCheckPoint();
333 }
334
335
FinalizeCode()336 void MacroAssembler::FinalizeCode() {
337 if (!literal_pool_.IsEmpty()) literal_pool_.Emit();
338 VIXL_ASSERT(veneer_pool_.IsEmpty());
339
340 Assembler::FinalizeCode();
341 }
342
343
CheckEmitFor(size_t amount)344 void MacroAssembler::CheckEmitFor(size_t amount) {
345 ptrdiff_t offset = amount;
346
347 literal_pool_.CheckEmitFor(amount);
348 veneer_pool_.CheckEmitFor(amount);
349 // Ensure there's enough space for the emit, keep in mind the cursor will
350 // have moved if a pool was emitted.
351 if ((CursorOffset() + offset) > BufferEndOffset()) {
352 EnsureSpaceFor(amount);
353 }
354
355 checkpoint_ = NextCheckPoint();
356 }
357
358
MoveImmediateHelper(MacroAssembler * masm,const Register & rd,uint64_t imm)359 int MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,
360 const Register &rd,
361 uint64_t imm) {
362 bool emit_code = (masm != NULL);
363 VIXL_ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits());
364 // The worst case for size is mov 64-bit immediate to sp:
365 // * up to 4 instructions to materialise the constant
366 // * 1 instruction to move to sp
367 MacroEmissionCheckScope guard(masm);
368
369 // Immediates on Aarch64 can be produced using an initial value, and zero to
370 // three move keep operations.
371 //
372 // Initial values can be generated with:
373 // 1. 64-bit move zero (movz).
374 // 2. 32-bit move inverted (movn).
375 // 3. 64-bit move inverted.
376 // 4. 32-bit orr immediate.
377 // 5. 64-bit orr immediate.
378 // Move-keep may then be used to modify each of the 16-bit half words.
379 //
380 // The code below supports all five initial value generators, and
381 // applying move-keep operations to move-zero and move-inverted initial
382 // values.
383
384 // Try to move the immediate in one instruction, and if that fails, switch to
385 // using multiple instructions.
386 if (OneInstrMoveImmediateHelper(masm, rd, imm)) {
387 return 1;
388 } else {
389 int instruction_count = 0;
390 unsigned reg_size = rd.size();
391
392 // Generic immediate case. Imm will be represented by
393 // [imm3, imm2, imm1, imm0], where each imm is 16 bits.
394 // A move-zero or move-inverted is generated for the first non-zero or
395 // non-0xffff immX, and a move-keep for subsequent non-zero immX.
396
397 uint64_t ignored_halfword = 0;
398 bool invert_move = false;
399 // If the number of 0xffff halfwords is greater than the number of 0x0000
400 // halfwords, it's more efficient to use move-inverted.
401 if (CountClearHalfWords(~imm, reg_size) >
402 CountClearHalfWords(imm, reg_size)) {
403 ignored_halfword = 0xffff;
404 invert_move = true;
405 }
406
407 // Mov instructions can't move values into the stack pointer, so set up a
408 // temporary register, if needed.
409 UseScratchRegisterScope temps;
410 Register temp;
411 if (emit_code) {
412 temps.Open(masm);
413 temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
414 }
415
416 // Iterate through the halfwords. Use movn/movz for the first non-ignored
417 // halfword, and movk for subsequent halfwords.
418 VIXL_ASSERT((reg_size % 16) == 0);
419 bool first_mov_done = false;
420 for (unsigned i = 0; i < (temp.size() / 16); i++) {
421 uint64_t imm16 = (imm >> (16 * i)) & 0xffff;
422 if (imm16 != ignored_halfword) {
423 if (!first_mov_done) {
424 if (invert_move) {
425 if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);
426 instruction_count++;
427 } else {
428 if (emit_code) masm->movz(temp, imm16, 16 * i);
429 instruction_count++;
430 }
431 first_mov_done = true;
432 } else {
433 // Construct a wider constant.
434 if (emit_code) masm->movk(temp, imm16, 16 * i);
435 instruction_count++;
436 }
437 }
438 }
439
440 VIXL_ASSERT(first_mov_done);
441
442 // Move the temporary if the original destination register was the stack
443 // pointer.
444 if (rd.IsSP()) {
445 if (emit_code) masm->mov(rd, temp);
446 instruction_count++;
447 }
448 return instruction_count;
449 }
450 }
451
452
OneInstrMoveImmediateHelper(MacroAssembler * masm,const Register & dst,int64_t imm)453 bool MacroAssembler::OneInstrMoveImmediateHelper(MacroAssembler* masm,
454 const Register& dst,
455 int64_t imm) {
456 bool emit_code = masm != NULL;
457 unsigned n, imm_s, imm_r;
458 int reg_size = dst.size();
459
460 if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
461 // Immediate can be represented in a move zero instruction. Movz can't write
462 // to the stack pointer.
463 if (emit_code) {
464 masm->movz(dst, imm);
465 }
466 return true;
467 } else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
468 // Immediate can be represented in a move negative instruction. Movn can't
469 // write to the stack pointer.
470 if (emit_code) {
471 masm->movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
472 }
473 return true;
474 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
475 // Immediate can be represented in a logical orr instruction.
476 VIXL_ASSERT(!dst.IsZero());
477 if (emit_code) {
478 masm->LogicalImmediate(
479 dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR);
480 }
481 return true;
482 }
483 return false;
484 }
485
486
B(Label * label,BranchType type,Register reg,int bit)487 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
488 VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&
489 ((bit == -1) || (type >= kBranchTypeFirstUsingBit)));
490 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
491 B(static_cast<Condition>(type), label);
492 } else {
493 switch (type) {
494 case always: B(label); break;
495 case never: break;
496 case reg_zero: Cbz(reg, label); break;
497 case reg_not_zero: Cbnz(reg, label); break;
498 case reg_bit_clear: Tbz(reg, bit, label); break;
499 case reg_bit_set: Tbnz(reg, bit, label); break;
500 default:
501 VIXL_UNREACHABLE();
502 }
503 }
504 }
505
506
B(Label * label)507 void MacroAssembler::B(Label* label) {
508 SingleEmissionCheckScope guard(this);
509 b(label);
510 }
511
512
B(Label * label,Condition cond)513 void MacroAssembler::B(Label* label, Condition cond) {
514 VIXL_ASSERT(allow_macro_instructions_);
515 VIXL_ASSERT((cond != al) && (cond != nv));
516 EmissionCheckScope guard(this, 2 * kInstructionSize);
517
518 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
519 Label done;
520 b(&done, InvertCondition(cond));
521 b(label);
522 bind(&done);
523 } else {
524 if (!label->IsBound()) {
525 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
526 label,
527 CondBranchType);
528 }
529 b(label, cond);
530 }
531 }
532
533
Cbnz(const Register & rt,Label * label)534 void MacroAssembler::Cbnz(const Register& rt, Label* label) {
535 VIXL_ASSERT(allow_macro_instructions_);
536 VIXL_ASSERT(!rt.IsZero());
537 EmissionCheckScope guard(this, 2 * kInstructionSize);
538
539 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
540 Label done;
541 cbz(rt, &done);
542 b(label);
543 bind(&done);
544 } else {
545 if (!label->IsBound()) {
546 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
547 label,
548 CompareBranchType);
549 }
550 cbnz(rt, label);
551 }
552 }
553
554
Cbz(const Register & rt,Label * label)555 void MacroAssembler::Cbz(const Register& rt, Label* label) {
556 VIXL_ASSERT(allow_macro_instructions_);
557 VIXL_ASSERT(!rt.IsZero());
558 EmissionCheckScope guard(this, 2 * kInstructionSize);
559
560 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
561 Label done;
562 cbnz(rt, &done);
563 b(label);
564 bind(&done);
565 } else {
566 if (!label->IsBound()) {
567 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
568 label,
569 CompareBranchType);
570 }
571 cbz(rt, label);
572 }
573 }
574
575
Tbnz(const Register & rt,unsigned bit_pos,Label * label)576 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
577 VIXL_ASSERT(allow_macro_instructions_);
578 VIXL_ASSERT(!rt.IsZero());
579 EmissionCheckScope guard(this, 2 * kInstructionSize);
580
581 if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
582 Label done;
583 tbz(rt, bit_pos, &done);
584 b(label);
585 bind(&done);
586 } else {
587 if (!label->IsBound()) {
588 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
589 label,
590 TestBranchType);
591 }
592 tbnz(rt, bit_pos, label);
593 }
594 }
595
596
Tbz(const Register & rt,unsigned bit_pos,Label * label)597 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
598 VIXL_ASSERT(allow_macro_instructions_);
599 VIXL_ASSERT(!rt.IsZero());
600 EmissionCheckScope guard(this, 2 * kInstructionSize);
601
602 if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
603 Label done;
604 tbnz(rt, bit_pos, &done);
605 b(label);
606 bind(&done);
607 } else {
608 if (!label->IsBound()) {
609 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
610 label,
611 TestBranchType);
612 }
613 tbz(rt, bit_pos, label);
614 }
615 }
616
617
Bind(Label * label)618 void MacroAssembler::Bind(Label* label) {
619 VIXL_ASSERT(allow_macro_instructions_);
620 veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
621 bind(label);
622 }
623
624
625 // Bind a label to a specified offset from the start of the buffer.
BindToOffset(Label * label,ptrdiff_t offset)626 void MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {
627 VIXL_ASSERT(allow_macro_instructions_);
628 veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
629 Assembler::BindToOffset(label, offset);
630 }
631
632
And(const Register & rd,const Register & rn,const Operand & operand)633 void MacroAssembler::And(const Register& rd,
634 const Register& rn,
635 const Operand& operand) {
636 VIXL_ASSERT(allow_macro_instructions_);
637 LogicalMacro(rd, rn, operand, AND);
638 }
639
640
Ands(const Register & rd,const Register & rn,const Operand & operand)641 void MacroAssembler::Ands(const Register& rd,
642 const Register& rn,
643 const Operand& operand) {
644 VIXL_ASSERT(allow_macro_instructions_);
645 LogicalMacro(rd, rn, operand, ANDS);
646 }
647
648
Tst(const Register & rn,const Operand & operand)649 void MacroAssembler::Tst(const Register& rn,
650 const Operand& operand) {
651 VIXL_ASSERT(allow_macro_instructions_);
652 Ands(AppropriateZeroRegFor(rn), rn, operand);
653 }
654
655
Bic(const Register & rd,const Register & rn,const Operand & operand)656 void MacroAssembler::Bic(const Register& rd,
657 const Register& rn,
658 const Operand& operand) {
659 VIXL_ASSERT(allow_macro_instructions_);
660 LogicalMacro(rd, rn, operand, BIC);
661 }
662
663
Bics(const Register & rd,const Register & rn,const Operand & operand)664 void MacroAssembler::Bics(const Register& rd,
665 const Register& rn,
666 const Operand& operand) {
667 VIXL_ASSERT(allow_macro_instructions_);
668 LogicalMacro(rd, rn, operand, BICS);
669 }
670
671
Orr(const Register & rd,const Register & rn,const Operand & operand)672 void MacroAssembler::Orr(const Register& rd,
673 const Register& rn,
674 const Operand& operand) {
675 VIXL_ASSERT(allow_macro_instructions_);
676 LogicalMacro(rd, rn, operand, ORR);
677 }
678
679
Orn(const Register & rd,const Register & rn,const Operand & operand)680 void MacroAssembler::Orn(const Register& rd,
681 const Register& rn,
682 const Operand& operand) {
683 VIXL_ASSERT(allow_macro_instructions_);
684 LogicalMacro(rd, rn, operand, ORN);
685 }
686
687
Eor(const Register & rd,const Register & rn,const Operand & operand)688 void MacroAssembler::Eor(const Register& rd,
689 const Register& rn,
690 const Operand& operand) {
691 VIXL_ASSERT(allow_macro_instructions_);
692 LogicalMacro(rd, rn, operand, EOR);
693 }
694
695
Eon(const Register & rd,const Register & rn,const Operand & operand)696 void MacroAssembler::Eon(const Register& rd,
697 const Register& rn,
698 const Operand& operand) {
699 VIXL_ASSERT(allow_macro_instructions_);
700 LogicalMacro(rd, rn, operand, EON);
701 }
702
703
LogicalMacro(const Register & rd,const Register & rn,const Operand & operand,LogicalOp op)704 void MacroAssembler::LogicalMacro(const Register& rd,
705 const Register& rn,
706 const Operand& operand,
707 LogicalOp op) {
708 // The worst case for size is logical immediate to sp:
709 // * up to 4 instructions to materialise the constant
710 // * 1 instruction to do the operation
711 // * 1 instruction to move to sp
712 MacroEmissionCheckScope guard(this);
713 UseScratchRegisterScope temps(this);
714
715 if (operand.IsImmediate()) {
716 int64_t immediate = operand.immediate();
717 unsigned reg_size = rd.size();
718
719 // If the operation is NOT, invert the operation and immediate.
720 if ((op & NOT) == NOT) {
721 op = static_cast<LogicalOp>(op & ~NOT);
722 immediate = ~immediate;
723 }
724
725 // Ignore the top 32 bits of an immediate if we're moving to a W register.
726 if (rd.Is32Bits()) {
727 // Check that the top 32 bits are consistent.
728 VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||
729 ((immediate >> kWRegSize) == -1));
730 immediate &= kWRegMask;
731 }
732
733 VIXL_ASSERT(rd.Is64Bits() || is_uint32(immediate));
734
735 // Special cases for all set or all clear immediates.
736 if (immediate == 0) {
737 switch (op) {
738 case AND:
739 Mov(rd, 0);
740 return;
741 case ORR:
742 VIXL_FALLTHROUGH();
743 case EOR:
744 Mov(rd, rn);
745 return;
746 case ANDS:
747 VIXL_FALLTHROUGH();
748 case BICS:
749 break;
750 default:
751 VIXL_UNREACHABLE();
752 }
753 } else if ((rd.Is64Bits() && (immediate == -1)) ||
754 (rd.Is32Bits() && (immediate == 0xffffffff))) {
755 switch (op) {
756 case AND:
757 Mov(rd, rn);
758 return;
759 case ORR:
760 Mov(rd, immediate);
761 return;
762 case EOR:
763 Mvn(rd, rn);
764 return;
765 case ANDS:
766 VIXL_FALLTHROUGH();
767 case BICS:
768 break;
769 default:
770 VIXL_UNREACHABLE();
771 }
772 }
773
774 unsigned n, imm_s, imm_r;
775 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
776 // Immediate can be encoded in the instruction.
777 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
778 } else {
779 // Immediate can't be encoded: synthesize using move immediate.
780 Register temp = temps.AcquireSameSizeAs(rn);
781 Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
782
783 if (rd.Is(sp)) {
784 // If rd is the stack pointer we cannot use it as the destination
785 // register so we use the temp register as an intermediate again.
786 Logical(temp, rn, imm_operand, op);
787 Mov(sp, temp);
788 } else {
789 Logical(rd, rn, imm_operand, op);
790 }
791 }
792 } else if (operand.IsExtendedRegister()) {
793 VIXL_ASSERT(operand.reg().size() <= rd.size());
794 // Add/sub extended supports shift <= 4. We want to support exactly the
795 // same modes here.
796 VIXL_ASSERT(operand.shift_amount() <= 4);
797 VIXL_ASSERT(operand.reg().Is64Bits() ||
798 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
799
800 temps.Exclude(operand.reg());
801 Register temp = temps.AcquireSameSizeAs(rn);
802 EmitExtendShift(temp, operand.reg(), operand.extend(),
803 operand.shift_amount());
804 Logical(rd, rn, Operand(temp), op);
805 } else {
806 // The operand can be encoded in the instruction.
807 VIXL_ASSERT(operand.IsShiftedRegister());
808 Logical(rd, rn, operand, op);
809 }
810 }
811
812
Mov(const Register & rd,const Operand & operand,DiscardMoveMode discard_mode)813 void MacroAssembler::Mov(const Register& rd,
814 const Operand& operand,
815 DiscardMoveMode discard_mode) {
816 VIXL_ASSERT(allow_macro_instructions_);
817 // The worst case for size is mov immediate with up to 4 instructions.
818 MacroEmissionCheckScope guard(this);
819
820 if (operand.IsImmediate()) {
821 // Call the macro assembler for generic immediates.
822 Mov(rd, operand.immediate());
823 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
824 // Emit a shift instruction if moving a shifted register. This operation
825 // could also be achieved using an orr instruction (like orn used by Mvn),
826 // but using a shift instruction makes the disassembly clearer.
827 EmitShift(rd, operand.reg(), operand.shift(), operand.shift_amount());
828 } else if (operand.IsExtendedRegister()) {
829 // Emit an extend instruction if moving an extended register. This handles
830 // extend with post-shift operations, too.
831 EmitExtendShift(rd, operand.reg(), operand.extend(),
832 operand.shift_amount());
833 } else {
834 // Otherwise, emit a register move only if the registers are distinct, or
835 // if they are not X registers.
836 //
837 // Note that mov(w0, w0) is not a no-op because it clears the top word of
838 // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W
839 // registers is not required to clear the top word of the X register. In
840 // this case, the instruction is discarded.
841 //
842 // If the sp is an operand, add #0 is emitted, otherwise, orr #0.
843 if (!rd.Is(operand.reg()) || (rd.Is32Bits() &&
844 (discard_mode == kDontDiscardForSameWReg))) {
845 mov(rd, operand.reg());
846 }
847 }
848 }
849
850
Movi16bitHelper(const VRegister & vd,uint64_t imm)851 void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {
852 VIXL_ASSERT(is_uint16(imm));
853 int byte1 = (imm & 0xff);
854 int byte2 = ((imm >> 8) & 0xff);
855 if (byte1 == byte2) {
856 movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);
857 } else if (byte1 == 0) {
858 movi(vd, byte2, LSL, 8);
859 } else if (byte2 == 0) {
860 movi(vd, byte1);
861 } else if (byte1 == 0xff) {
862 mvni(vd, ~byte2 & 0xff, LSL, 8);
863 } else if (byte2 == 0xff) {
864 mvni(vd, ~byte1 & 0xff);
865 } else {
866 UseScratchRegisterScope temps(this);
867 Register temp = temps.AcquireW();
868 movz(temp, imm);
869 dup(vd, temp);
870 }
871 }
872
873
Movi32bitHelper(const VRegister & vd,uint64_t imm)874 void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {
875 VIXL_ASSERT(is_uint32(imm));
876
877 uint8_t bytes[sizeof(imm)];
878 memcpy(bytes, &imm, sizeof(imm));
879
880 // All bytes are either 0x00 or 0xff.
881 {
882 bool all0orff = true;
883 for (int i = 0; i < 4; ++i) {
884 if ((bytes[i] != 0) && (bytes[i] != 0xff)) {
885 all0orff = false;
886 break;
887 }
888 }
889
890 if (all0orff == true) {
891 movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));
892 return;
893 }
894 }
895
896 // Of the 4 bytes, only one byte is non-zero.
897 for (int i = 0; i < 4; i++) {
898 if ((imm & (0xff << (i * 8))) == imm) {
899 movi(vd, bytes[i], LSL, i * 8);
900 return;
901 }
902 }
903
904 // Of the 4 bytes, only one byte is not 0xff.
905 for (int i = 0; i < 4; i++) {
906 uint32_t mask = ~(0xff << (i * 8));
907 if ((imm & mask) == mask) {
908 mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);
909 return;
910 }
911 }
912
913 // Immediate is of the form 0x00MMFFFF.
914 if ((imm & 0xff00ffff) == 0x0000ffff) {
915 movi(vd, bytes[2], MSL, 16);
916 return;
917 }
918
919 // Immediate is of the form 0x0000MMFF.
920 if ((imm & 0xffff00ff) == 0x000000ff) {
921 movi(vd, bytes[1], MSL, 8);
922 return;
923 }
924
925 // Immediate is of the form 0xFFMM0000.
926 if ((imm & 0xff00ffff) == 0xff000000) {
927 mvni(vd, ~bytes[2] & 0xff, MSL, 16);
928 return;
929 }
930 // Immediate is of the form 0xFFFFMM00.
931 if ((imm & 0xffff00ff) == 0xffff0000) {
932 mvni(vd, ~bytes[1] & 0xff, MSL, 8);
933 return;
934 }
935
936 // Top and bottom 16-bits are equal.
937 if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {
938 Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);
939 return;
940 }
941
942 // Default case.
943 {
944 UseScratchRegisterScope temps(this);
945 Register temp = temps.AcquireW();
946 Mov(temp, imm);
947 dup(vd, temp);
948 }
949 }
950
951
Movi64bitHelper(const VRegister & vd,uint64_t imm)952 void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
953 // All bytes are either 0x00 or 0xff.
954 {
955 bool all0orff = true;
956 for (int i = 0; i < 8; ++i) {
957 int byteval = (imm >> (i * 8)) & 0xff;
958 if (byteval != 0 && byteval != 0xff) {
959 all0orff = false;
960 break;
961 }
962 }
963 if (all0orff == true) {
964 movi(vd, imm);
965 return;
966 }
967 }
968
969 // Top and bottom 32-bits are equal.
970 if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {
971 Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);
972 return;
973 }
974
975 // Default case.
976 {
977 UseScratchRegisterScope temps(this);
978 Register temp = temps.AcquireX();
979 Mov(temp, imm);
980 if (vd.Is1D()) {
981 mov(vd.D(), 0, temp);
982 } else {
983 dup(vd.V2D(), temp);
984 }
985 }
986 }
987
988
Movi(const VRegister & vd,uint64_t imm,Shift shift,int shift_amount)989 void MacroAssembler::Movi(const VRegister& vd,
990 uint64_t imm,
991 Shift shift,
992 int shift_amount) {
993 VIXL_ASSERT(allow_macro_instructions_);
994 MacroEmissionCheckScope guard(this);
995 if (shift_amount != 0 || shift != LSL) {
996 movi(vd, imm, shift, shift_amount);
997 } else if (vd.Is8B() || vd.Is16B()) {
998 // 8-bit immediate.
999 VIXL_ASSERT(is_uint8(imm));
1000 movi(vd, imm);
1001 } else if (vd.Is4H() || vd.Is8H()) {
1002 // 16-bit immediate.
1003 Movi16bitHelper(vd, imm);
1004 } else if (vd.Is2S() || vd.Is4S()) {
1005 // 32-bit immediate.
1006 Movi32bitHelper(vd, imm);
1007 } else {
1008 // 64-bit immediate.
1009 Movi64bitHelper(vd, imm);
1010 }
1011 }
1012
1013
Movi(const VRegister & vd,uint64_t hi,uint64_t lo)1014 void MacroAssembler::Movi(const VRegister& vd,
1015 uint64_t hi,
1016 uint64_t lo) {
1017 // TODO: Move 128-bit values in a more efficient way.
1018 VIXL_ASSERT(vd.Is128Bits());
1019 UseScratchRegisterScope temps(this);
1020 Movi(vd.V2D(), lo);
1021 Register temp = temps.AcquireX();
1022 Mov(temp, hi);
1023 Ins(vd.V2D(), 1, temp);
1024 }
1025
1026
Mvn(const Register & rd,const Operand & operand)1027 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
1028 VIXL_ASSERT(allow_macro_instructions_);
1029 // The worst case for size is mvn immediate with up to 4 instructions.
1030 MacroEmissionCheckScope guard(this);
1031
1032 if (operand.IsImmediate()) {
1033 // Call the macro assembler for generic immediates.
1034 Mvn(rd, operand.immediate());
1035 } else if (operand.IsExtendedRegister()) {
1036 UseScratchRegisterScope temps(this);
1037 temps.Exclude(operand.reg());
1038
1039 // Emit two instructions for the extend case. This differs from Mov, as
1040 // the extend and invert can't be achieved in one instruction.
1041 Register temp = temps.AcquireSameSizeAs(rd);
1042 EmitExtendShift(temp, operand.reg(), operand.extend(),
1043 operand.shift_amount());
1044 mvn(rd, Operand(temp));
1045 } else {
1046 // Otherwise, register and shifted register cases can be handled by the
1047 // assembler directly, using orn.
1048 mvn(rd, operand);
1049 }
1050 }
1051
1052
Mov(const Register & rd,uint64_t imm)1053 void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
1054 VIXL_ASSERT(allow_macro_instructions_);
1055 MoveImmediateHelper(this, rd, imm);
1056 }
1057
1058
Ccmp(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1059 void MacroAssembler::Ccmp(const Register& rn,
1060 const Operand& operand,
1061 StatusFlags nzcv,
1062 Condition cond) {
1063 VIXL_ASSERT(allow_macro_instructions_);
1064 if (operand.IsImmediate() && (operand.immediate() < 0)) {
1065 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN);
1066 } else {
1067 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
1068 }
1069 }
1070
1071
Ccmn(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond)1072 void MacroAssembler::Ccmn(const Register& rn,
1073 const Operand& operand,
1074 StatusFlags nzcv,
1075 Condition cond) {
1076 VIXL_ASSERT(allow_macro_instructions_);
1077 if (operand.IsImmediate() && (operand.immediate() < 0)) {
1078 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP);
1079 } else {
1080 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
1081 }
1082 }
1083
1084
ConditionalCompareMacro(const Register & rn,const Operand & operand,StatusFlags nzcv,Condition cond,ConditionalCompareOp op)1085 void MacroAssembler::ConditionalCompareMacro(const Register& rn,
1086 const Operand& operand,
1087 StatusFlags nzcv,
1088 Condition cond,
1089 ConditionalCompareOp op) {
1090 VIXL_ASSERT((cond != al) && (cond != nv));
1091 // The worst case for size is ccmp immediate:
1092 // * up to 4 instructions to materialise the constant
1093 // * 1 instruction for ccmp
1094 MacroEmissionCheckScope guard(this);
1095
1096 if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) ||
1097 (operand.IsImmediate() && IsImmConditionalCompare(operand.immediate()))) {
1098 // The immediate can be encoded in the instruction, or the operand is an
1099 // unshifted register: call the assembler.
1100 ConditionalCompare(rn, operand, nzcv, cond, op);
1101 } else {
1102 UseScratchRegisterScope temps(this);
1103 // The operand isn't directly supported by the instruction: perform the
1104 // operation on a temporary register.
1105 Register temp = temps.AcquireSameSizeAs(rn);
1106 Mov(temp, operand);
1107 ConditionalCompare(rn, temp, nzcv, cond, op);
1108 }
1109 }
1110
1111
Csel(const Register & rd,const Register & rn,const Operand & operand,Condition cond)1112 void MacroAssembler::Csel(const Register& rd,
1113 const Register& rn,
1114 const Operand& operand,
1115 Condition cond) {
1116 VIXL_ASSERT(allow_macro_instructions_);
1117 VIXL_ASSERT(!rd.IsZero());
1118 VIXL_ASSERT(!rn.IsZero());
1119 VIXL_ASSERT((cond != al) && (cond != nv));
1120 // The worst case for size is csel immediate:
1121 // * up to 4 instructions to materialise the constant
1122 // * 1 instruction for csel
1123 MacroEmissionCheckScope guard(this);
1124
1125 if (operand.IsImmediate()) {
1126 // Immediate argument. Handle special cases of 0, 1 and -1 using zero
1127 // register.
1128 int64_t imm = operand.immediate();
1129 Register zr = AppropriateZeroRegFor(rn);
1130 if (imm == 0) {
1131 csel(rd, rn, zr, cond);
1132 } else if (imm == 1) {
1133 csinc(rd, rn, zr, cond);
1134 } else if (imm == -1) {
1135 csinv(rd, rn, zr, cond);
1136 } else {
1137 UseScratchRegisterScope temps(this);
1138 Register temp = temps.AcquireSameSizeAs(rn);
1139 Mov(temp, operand.immediate());
1140 csel(rd, rn, temp, cond);
1141 }
1142 } else if (operand.IsShiftedRegister() && (operand.shift_amount() == 0)) {
1143 // Unshifted register argument.
1144 csel(rd, rn, operand.reg(), cond);
1145 } else {
1146 // All other arguments.
1147 UseScratchRegisterScope temps(this);
1148 Register temp = temps.AcquireSameSizeAs(rn);
1149 Mov(temp, operand);
1150 csel(rd, rn, temp, cond);
1151 }
1152 }
1153
1154
Add(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1155 void MacroAssembler::Add(const Register& rd,
1156 const Register& rn,
1157 const Operand& operand,
1158 FlagsUpdate S) {
1159 VIXL_ASSERT(allow_macro_instructions_);
1160 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1161 IsImmAddSub(-operand.immediate())) {
1162 AddSubMacro(rd, rn, -operand.immediate(), S, SUB);
1163 } else {
1164 AddSubMacro(rd, rn, operand, S, ADD);
1165 }
1166 }
1167
1168
Adds(const Register & rd,const Register & rn,const Operand & operand)1169 void MacroAssembler::Adds(const Register& rd,
1170 const Register& rn,
1171 const Operand& operand) {
1172 Add(rd, rn, operand, SetFlags);
1173 }
1174
1175
Sub(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S)1176 void MacroAssembler::Sub(const Register& rd,
1177 const Register& rn,
1178 const Operand& operand,
1179 FlagsUpdate S) {
1180 VIXL_ASSERT(allow_macro_instructions_);
1181 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1182 IsImmAddSub(-operand.immediate())) {
1183 AddSubMacro(rd, rn, -operand.immediate(), S, ADD);
1184 } else {
1185 AddSubMacro(rd, rn, operand, S, SUB);
1186 }
1187 }
1188
1189
Subs(const Register & rd,const Register & rn,const Operand & operand)1190 void MacroAssembler::Subs(const Register& rd,
1191 const Register& rn,
1192 const Operand& operand) {
1193 Sub(rd, rn, operand, SetFlags);
1194 }
1195
1196
Cmn(const Register & rn,const Operand & operand)1197 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
1198 VIXL_ASSERT(allow_macro_instructions_);
1199 Adds(AppropriateZeroRegFor(rn), rn, operand);
1200 }
1201
1202
Cmp(const Register & rn,const Operand & operand)1203 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
1204 VIXL_ASSERT(allow_macro_instructions_);
1205 Subs(AppropriateZeroRegFor(rn), rn, operand);
1206 }
1207
1208
Fcmp(const FPRegister & fn,double value,FPTrapFlags trap)1209 void MacroAssembler::Fcmp(const FPRegister& fn, double value,
1210 FPTrapFlags trap) {
1211 VIXL_ASSERT(allow_macro_instructions_);
1212 // The worst case for size is:
1213 // * 1 to materialise the constant, using literal pool if necessary
1214 // * 1 instruction for fcmp{e}
1215 MacroEmissionCheckScope guard(this);
1216 if (value != 0.0) {
1217 UseScratchRegisterScope temps(this);
1218 FPRegister tmp = temps.AcquireSameSizeAs(fn);
1219 Fmov(tmp, value);
1220 FPCompareMacro(fn, tmp, trap);
1221 } else {
1222 FPCompareMacro(fn, value, trap);
1223 }
1224 }
1225
1226
Fcmpe(const FPRegister & fn,double value)1227 void MacroAssembler::Fcmpe(const FPRegister& fn, double value) {
1228 Fcmp(fn, value, EnableTrap);
1229 }
1230
1231
Fmov(VRegister vd,double imm)1232 void MacroAssembler::Fmov(VRegister vd, double imm) {
1233 VIXL_ASSERT(allow_macro_instructions_);
1234 // Floating point immediates are loaded through the literal pool.
1235 MacroEmissionCheckScope guard(this);
1236
1237 if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1238 Fmov(vd, static_cast<float>(imm));
1239 return;
1240 }
1241
1242 VIXL_ASSERT(vd.Is1D() || vd.Is2D());
1243 if (IsImmFP64(imm)) {
1244 fmov(vd, imm);
1245 } else {
1246 uint64_t rawbits = double_to_rawbits(imm);
1247 if (vd.IsScalar()) {
1248 if (rawbits == 0) {
1249 fmov(vd, xzr);
1250 } else {
1251 ldr(vd,
1252 new Literal<double>(imm,
1253 &literal_pool_,
1254 RawLiteral::kDeletedOnPlacementByPool));
1255 }
1256 } else {
1257 // TODO: consider NEON support for load literal.
1258 Movi(vd, rawbits);
1259 }
1260 }
1261 }
1262
1263
Fmov(VRegister vd,float imm)1264 void MacroAssembler::Fmov(VRegister vd, float imm) {
1265 VIXL_ASSERT(allow_macro_instructions_);
1266 // Floating point immediates are loaded through the literal pool.
1267 MacroEmissionCheckScope guard(this);
1268
1269 if (vd.Is1D() || vd.Is2D()) {
1270 Fmov(vd, static_cast<double>(imm));
1271 return;
1272 }
1273
1274 VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
1275 if (IsImmFP32(imm)) {
1276 fmov(vd, imm);
1277 } else {
1278 uint32_t rawbits = float_to_rawbits(imm);
1279 if (vd.IsScalar()) {
1280 if (rawbits == 0) {
1281 fmov(vd, wzr);
1282 } else {
1283 ldr(vd,
1284 new Literal<float>(imm,
1285 &literal_pool_,
1286 RawLiteral::kDeletedOnPlacementByPool));
1287 }
1288 } else {
1289 // TODO: consider NEON support for load literal.
1290 Movi(vd, rawbits);
1291 }
1292 }
1293 }
1294
1295
1296
Neg(const Register & rd,const Operand & operand)1297 void MacroAssembler::Neg(const Register& rd,
1298 const Operand& operand) {
1299 VIXL_ASSERT(allow_macro_instructions_);
1300 if (operand.IsImmediate()) {
1301 Mov(rd, -operand.immediate());
1302 } else {
1303 Sub(rd, AppropriateZeroRegFor(rd), operand);
1304 }
1305 }
1306
1307
Negs(const Register & rd,const Operand & operand)1308 void MacroAssembler::Negs(const Register& rd,
1309 const Operand& operand) {
1310 VIXL_ASSERT(allow_macro_instructions_);
1311 Subs(rd, AppropriateZeroRegFor(rd), operand);
1312 }
1313
1314
TryOneInstrMoveImmediate(const Register & dst,int64_t imm)1315 bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
1316 int64_t imm) {
1317 return OneInstrMoveImmediateHelper(this, dst, imm);
1318 }
1319
1320
MoveImmediateForShiftedOp(const Register & dst,int64_t imm)1321 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
1322 int64_t imm) {
1323 int reg_size = dst.size();
1324
1325 // Encode the immediate in a single move instruction, if possible.
1326 if (TryOneInstrMoveImmediate(dst, imm)) {
1327 // The move was successful; nothing to do here.
1328 } else {
1329 // Pre-shift the immediate to the least-significant bits of the register.
1330 int shift_low = CountTrailingZeros(imm, reg_size);
1331 int64_t imm_low = imm >> shift_low;
1332
1333 // Pre-shift the immediate to the most-significant bits of the register,
1334 // inserting set bits in the least-significant bits.
1335 int shift_high = CountLeadingZeros(imm, reg_size);
1336 int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
1337
1338 if (TryOneInstrMoveImmediate(dst, imm_low)) {
1339 // The new immediate has been moved into the destination's low bits:
1340 // return a new leftward-shifting operand.
1341 return Operand(dst, LSL, shift_low);
1342 } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
1343 // The new immediate has been moved into the destination's high bits:
1344 // return a new rightward-shifting operand.
1345 return Operand(dst, LSR, shift_high);
1346 } else {
1347 Mov(dst, imm);
1348 }
1349 }
1350 return Operand(dst);
1351 }
1352
1353
ComputeAddress(const Register & dst,const MemOperand & mem_op)1354 void MacroAssembler::ComputeAddress(const Register& dst,
1355 const MemOperand& mem_op) {
1356 // We cannot handle pre-indexing or post-indexing.
1357 VIXL_ASSERT(mem_op.addrmode() == Offset);
1358 Register base = mem_op.base();
1359 if (mem_op.IsImmediateOffset()) {
1360 Add(dst, base, mem_op.offset());
1361 } else {
1362 VIXL_ASSERT(mem_op.IsRegisterOffset());
1363 Register reg_offset = mem_op.regoffset();
1364 Shift shift = mem_op.shift();
1365 Extend extend = mem_op.extend();
1366 if (shift == NO_SHIFT) {
1367 VIXL_ASSERT(extend != NO_EXTEND);
1368 Add(dst, base, Operand(reg_offset, extend, mem_op.shift_amount()));
1369 } else {
1370 VIXL_ASSERT(extend == NO_EXTEND);
1371 Add(dst, base, Operand(reg_offset, shift, mem_op.shift_amount()));
1372 }
1373 }
1374 }
1375
1376
AddSubMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubOp op)1377 void MacroAssembler::AddSubMacro(const Register& rd,
1378 const Register& rn,
1379 const Operand& operand,
1380 FlagsUpdate S,
1381 AddSubOp op) {
1382 // Worst case is add/sub immediate:
1383 // * up to 4 instructions to materialise the constant
1384 // * 1 instruction for add/sub
1385 MacroEmissionCheckScope guard(this);
1386
1387 if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1388 (S == LeaveFlags)) {
1389 // The instruction would be a nop. Avoid generating useless code.
1390 return;
1391 }
1392
1393 if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
1394 (rn.IsZero() && !operand.IsShiftedRegister()) ||
1395 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1396 UseScratchRegisterScope temps(this);
1397 Register temp = temps.AcquireSameSizeAs(rn);
1398 if (operand.IsImmediate()) {
1399 Operand imm_operand =
1400 MoveImmediateForShiftedOp(temp, operand.immediate());
1401 AddSub(rd, rn, imm_operand, S, op);
1402 } else {
1403 Mov(temp, operand);
1404 AddSub(rd, rn, temp, S, op);
1405 }
1406 } else {
1407 AddSub(rd, rn, operand, S, op);
1408 }
1409 }
1410
1411
Adc(const Register & rd,const Register & rn,const Operand & operand)1412 void MacroAssembler::Adc(const Register& rd,
1413 const Register& rn,
1414 const Operand& operand) {
1415 VIXL_ASSERT(allow_macro_instructions_);
1416 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1417 }
1418
1419
Adcs(const Register & rd,const Register & rn,const Operand & operand)1420 void MacroAssembler::Adcs(const Register& rd,
1421 const Register& rn,
1422 const Operand& operand) {
1423 VIXL_ASSERT(allow_macro_instructions_);
1424 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
1425 }
1426
1427
Sbc(const Register & rd,const Register & rn,const Operand & operand)1428 void MacroAssembler::Sbc(const Register& rd,
1429 const Register& rn,
1430 const Operand& operand) {
1431 VIXL_ASSERT(allow_macro_instructions_);
1432 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1433 }
1434
1435
Sbcs(const Register & rd,const Register & rn,const Operand & operand)1436 void MacroAssembler::Sbcs(const Register& rd,
1437 const Register& rn,
1438 const Operand& operand) {
1439 VIXL_ASSERT(allow_macro_instructions_);
1440 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
1441 }
1442
1443
Ngc(const Register & rd,const Operand & operand)1444 void MacroAssembler::Ngc(const Register& rd,
1445 const Operand& operand) {
1446 VIXL_ASSERT(allow_macro_instructions_);
1447 Register zr = AppropriateZeroRegFor(rd);
1448 Sbc(rd, zr, operand);
1449 }
1450
1451
Ngcs(const Register & rd,const Operand & operand)1452 void MacroAssembler::Ngcs(const Register& rd,
1453 const Operand& operand) {
1454 VIXL_ASSERT(allow_macro_instructions_);
1455 Register zr = AppropriateZeroRegFor(rd);
1456 Sbcs(rd, zr, operand);
1457 }
1458
1459
AddSubWithCarryMacro(const Register & rd,const Register & rn,const Operand & operand,FlagsUpdate S,AddSubWithCarryOp op)1460 void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1461 const Register& rn,
1462 const Operand& operand,
1463 FlagsUpdate S,
1464 AddSubWithCarryOp op) {
1465 VIXL_ASSERT(rd.size() == rn.size());
1466 // Worst case is addc/subc immediate:
1467 // * up to 4 instructions to materialise the constant
1468 // * 1 instruction for add/sub
1469 MacroEmissionCheckScope guard(this);
1470 UseScratchRegisterScope temps(this);
1471
1472 if (operand.IsImmediate() ||
1473 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1474 // Add/sub with carry (immediate or ROR shifted register.)
1475 Register temp = temps.AcquireSameSizeAs(rn);
1476 Mov(temp, operand);
1477 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1478 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
1479 // Add/sub with carry (shifted register).
1480 VIXL_ASSERT(operand.reg().size() == rd.size());
1481 VIXL_ASSERT(operand.shift() != ROR);
1482 VIXL_ASSERT(is_uintn(rd.size() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
1483 operand.shift_amount()));
1484 temps.Exclude(operand.reg());
1485 Register temp = temps.AcquireSameSizeAs(rn);
1486 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
1487 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1488 } else if (operand.IsExtendedRegister()) {
1489 // Add/sub with carry (extended register).
1490 VIXL_ASSERT(operand.reg().size() <= rd.size());
1491 // Add/sub extended supports a shift <= 4. We want to support exactly the
1492 // same modes.
1493 VIXL_ASSERT(operand.shift_amount() <= 4);
1494 VIXL_ASSERT(operand.reg().Is64Bits() ||
1495 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
1496 temps.Exclude(operand.reg());
1497 Register temp = temps.AcquireSameSizeAs(rn);
1498 EmitExtendShift(temp, operand.reg(), operand.extend(),
1499 operand.shift_amount());
1500 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1501 } else {
1502 // The addressing mode is directly supported by the instruction.
1503 AddSubWithCarry(rd, rn, operand, S, op);
1504 }
1505 }
1506
1507
1508 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
1509 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
1510 VIXL_ASSERT(allow_macro_instructions_); \
1511 LoadStoreMacro(REG, addr, OP); \
1512 }
LS_MACRO_LIST(DEFINE_FUNCTION)1513 LS_MACRO_LIST(DEFINE_FUNCTION)
1514 #undef DEFINE_FUNCTION
1515
1516
1517 void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
1518 const MemOperand& addr,
1519 LoadStoreOp op) {
1520 // Worst case is ldr/str pre/post index:
1521 // * 1 instruction for ldr/str
1522 // * up to 4 instructions to materialise the constant
1523 // * 1 instruction to update the base
1524 MacroEmissionCheckScope guard(this);
1525
1526 int64_t offset = addr.offset();
1527 unsigned access_size = CalcLSDataSize(op);
1528
1529 // Check if an immediate offset fits in the immediate field of the
1530 // appropriate instruction. If not, emit two instructions to perform
1531 // the operation.
1532 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
1533 !IsImmLSUnscaled(offset)) {
1534 // Immediate offset that can't be encoded using unsigned or unscaled
1535 // addressing modes.
1536 UseScratchRegisterScope temps(this);
1537 Register temp = temps.AcquireSameSizeAs(addr.base());
1538 Mov(temp, addr.offset());
1539 LoadStore(rt, MemOperand(addr.base(), temp), op);
1540 } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
1541 // Post-index beyond unscaled addressing range.
1542 LoadStore(rt, MemOperand(addr.base()), op);
1543 Add(addr.base(), addr.base(), Operand(offset));
1544 } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
1545 // Pre-index beyond unscaled addressing range.
1546 Add(addr.base(), addr.base(), Operand(offset));
1547 LoadStore(rt, MemOperand(addr.base()), op);
1548 } else {
1549 // Encodable in one load/store instruction.
1550 LoadStore(rt, addr, op);
1551 }
1552 }
1553
1554
1555 #define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
1556 void MacroAssembler::FN(const REGTYPE REG, \
1557 const REGTYPE REG2, \
1558 const MemOperand& addr) { \
1559 VIXL_ASSERT(allow_macro_instructions_); \
1560 LoadStorePairMacro(REG, REG2, addr, OP); \
1561 }
LSPAIR_MACRO_LIST(DEFINE_FUNCTION)1562 LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
1563 #undef DEFINE_FUNCTION
1564
1565 void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
1566 const CPURegister& rt2,
1567 const MemOperand& addr,
1568 LoadStorePairOp op) {
1569 // TODO(all): Should we support register offset for load-store-pair?
1570 VIXL_ASSERT(!addr.IsRegisterOffset());
1571 // Worst case is ldp/stp immediate:
1572 // * 1 instruction for ldp/stp
1573 // * up to 4 instructions to materialise the constant
1574 // * 1 instruction to update the base
1575 MacroEmissionCheckScope guard(this);
1576
1577 int64_t offset = addr.offset();
1578 unsigned access_size = CalcLSPairDataSize(op);
1579
1580 // Check if the offset fits in the immediate field of the appropriate
1581 // instruction. If not, emit two instructions to perform the operation.
1582 if (IsImmLSPair(offset, access_size)) {
1583 // Encodable in one load/store pair instruction.
1584 LoadStorePair(rt, rt2, addr, op);
1585 } else {
1586 Register base = addr.base();
1587 if (addr.IsImmediateOffset()) {
1588 UseScratchRegisterScope temps(this);
1589 Register temp = temps.AcquireSameSizeAs(base);
1590 Add(temp, base, offset);
1591 LoadStorePair(rt, rt2, MemOperand(temp), op);
1592 } else if (addr.IsPostIndex()) {
1593 LoadStorePair(rt, rt2, MemOperand(base), op);
1594 Add(base, base, offset);
1595 } else {
1596 VIXL_ASSERT(addr.IsPreIndex());
1597 Add(base, base, offset);
1598 LoadStorePair(rt, rt2, MemOperand(base), op);
1599 }
1600 }
1601 }
1602
1603
Prfm(PrefetchOperation op,const MemOperand & addr)1604 void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
1605 MacroEmissionCheckScope guard(this);
1606
1607 // There are no pre- or post-index modes for prfm.
1608 VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
1609
1610 // The access size is implicitly 8 bytes for all prefetch operations.
1611 unsigned size = kXRegSizeInBytesLog2;
1612
1613 // Check if an immediate offset fits in the immediate field of the
1614 // appropriate instruction. If not, emit two instructions to perform
1615 // the operation.
1616 if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.offset(), size) &&
1617 !IsImmLSUnscaled(addr.offset())) {
1618 // Immediate offset that can't be encoded using unsigned or unscaled
1619 // addressing modes.
1620 UseScratchRegisterScope temps(this);
1621 Register temp = temps.AcquireSameSizeAs(addr.base());
1622 Mov(temp, addr.offset());
1623 Prefetch(op, MemOperand(addr.base(), temp));
1624 } else {
1625 // Simple register-offsets are encodable in one instruction.
1626 Prefetch(op, addr);
1627 }
1628 }
1629
1630
Push(const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)1631 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
1632 const CPURegister& src2, const CPURegister& src3) {
1633 VIXL_ASSERT(allow_macro_instructions_);
1634 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1635 VIXL_ASSERT(src0.IsValid());
1636
1637 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
1638 int size = src0.SizeInBytes();
1639
1640 PrepareForPush(count, size);
1641 PushHelper(count, size, src0, src1, src2, src3);
1642 }
1643
1644
Pop(const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)1645 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1,
1646 const CPURegister& dst2, const CPURegister& dst3) {
1647 // It is not valid to pop into the same register more than once in one
1648 // instruction, not even into the zero register.
1649 VIXL_ASSERT(allow_macro_instructions_);
1650 VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
1651 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1652 VIXL_ASSERT(dst0.IsValid());
1653
1654 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
1655 int size = dst0.SizeInBytes();
1656
1657 PrepareForPop(count, size);
1658 PopHelper(count, size, dst0, dst1, dst2, dst3);
1659 }
1660
1661
PushCPURegList(CPURegList registers)1662 void MacroAssembler::PushCPURegList(CPURegList registers) {
1663 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1664 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
1665 VIXL_ASSERT(allow_macro_instructions_);
1666
1667 int reg_size = registers.RegisterSizeInBytes();
1668 PrepareForPush(registers.Count(), reg_size);
1669
1670 // Bump the stack pointer and store two registers at the bottom.
1671 int size = registers.TotalSizeInBytes();
1672 const CPURegister& bottom_0 = registers.PopLowestIndex();
1673 const CPURegister& bottom_1 = registers.PopLowestIndex();
1674 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1675 Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
1676 } else if (bottom_0.IsValid()) {
1677 Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
1678 }
1679
1680 int offset = 2 * reg_size;
1681 while (!registers.IsEmpty()) {
1682 const CPURegister& src0 = registers.PopLowestIndex();
1683 const CPURegister& src1 = registers.PopLowestIndex();
1684 if (src1.IsValid()) {
1685 Stp(src0, src1, MemOperand(StackPointer(), offset));
1686 } else {
1687 Str(src0, MemOperand(StackPointer(), offset));
1688 }
1689 offset += 2 * reg_size;
1690 }
1691 }
1692
1693
PopCPURegList(CPURegList registers)1694 void MacroAssembler::PopCPURegList(CPURegList registers) {
1695 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1696 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
1697 VIXL_ASSERT(allow_macro_instructions_);
1698
1699 int reg_size = registers.RegisterSizeInBytes();
1700 PrepareForPop(registers.Count(), reg_size);
1701
1702
1703 int size = registers.TotalSizeInBytes();
1704 const CPURegister& bottom_0 = registers.PopLowestIndex();
1705 const CPURegister& bottom_1 = registers.PopLowestIndex();
1706
1707 int offset = 2 * reg_size;
1708 while (!registers.IsEmpty()) {
1709 const CPURegister& dst0 = registers.PopLowestIndex();
1710 const CPURegister& dst1 = registers.PopLowestIndex();
1711 if (dst1.IsValid()) {
1712 Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
1713 } else {
1714 Ldr(dst0, MemOperand(StackPointer(), offset));
1715 }
1716 offset += 2 * reg_size;
1717 }
1718
1719 // Load the two registers at the bottom and drop the stack pointer.
1720 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1721 Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
1722 } else if (bottom_0.IsValid()) {
1723 Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
1724 }
1725 }
1726
1727
PushMultipleTimes(int count,Register src)1728 void MacroAssembler::PushMultipleTimes(int count, Register src) {
1729 VIXL_ASSERT(allow_macro_instructions_);
1730 int size = src.SizeInBytes();
1731
1732 PrepareForPush(count, size);
1733 // Push up to four registers at a time if possible because if the current
1734 // stack pointer is sp and the register size is 32, registers must be pushed
1735 // in blocks of four in order to maintain the 16-byte alignment for sp.
1736 while (count >= 4) {
1737 PushHelper(4, size, src, src, src, src);
1738 count -= 4;
1739 }
1740 if (count >= 2) {
1741 PushHelper(2, size, src, src, NoReg, NoReg);
1742 count -= 2;
1743 }
1744 if (count == 1) {
1745 PushHelper(1, size, src, NoReg, NoReg, NoReg);
1746 count -= 1;
1747 }
1748 VIXL_ASSERT(count == 0);
1749 }
1750
1751
PushHelper(int count,int size,const CPURegister & src0,const CPURegister & src1,const CPURegister & src2,const CPURegister & src3)1752 void MacroAssembler::PushHelper(int count, int size,
1753 const CPURegister& src0,
1754 const CPURegister& src1,
1755 const CPURegister& src2,
1756 const CPURegister& src3) {
1757 // Ensure that we don't unintentionally modify scratch or debug registers.
1758 // Worst case for size is 2 stp.
1759 InstructionAccurateScope scope(this, 2,
1760 InstructionAccurateScope::kMaximumSize);
1761
1762 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1763 VIXL_ASSERT(size == src0.SizeInBytes());
1764
1765 // When pushing multiple registers, the store order is chosen such that
1766 // Push(a, b) is equivalent to Push(a) followed by Push(b).
1767 switch (count) {
1768 case 1:
1769 VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
1770 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
1771 break;
1772 case 2:
1773 VIXL_ASSERT(src2.IsNone() && src3.IsNone());
1774 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
1775 break;
1776 case 3:
1777 VIXL_ASSERT(src3.IsNone());
1778 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
1779 str(src0, MemOperand(StackPointer(), 2 * size));
1780 break;
1781 case 4:
1782 // Skip over 4 * size, then fill in the gap. This allows four W registers
1783 // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
1784 // all times.
1785 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
1786 stp(src1, src0, MemOperand(StackPointer(), 2 * size));
1787 break;
1788 default:
1789 VIXL_UNREACHABLE();
1790 }
1791 }
1792
1793
PopHelper(int count,int size,const CPURegister & dst0,const CPURegister & dst1,const CPURegister & dst2,const CPURegister & dst3)1794 void MacroAssembler::PopHelper(int count, int size,
1795 const CPURegister& dst0,
1796 const CPURegister& dst1,
1797 const CPURegister& dst2,
1798 const CPURegister& dst3) {
1799 // Ensure that we don't unintentionally modify scratch or debug registers.
1800 // Worst case for size is 2 ldp.
1801 InstructionAccurateScope scope(this, 2,
1802 InstructionAccurateScope::kMaximumSize);
1803
1804 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1805 VIXL_ASSERT(size == dst0.SizeInBytes());
1806
1807 // When popping multiple registers, the load order is chosen such that
1808 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
1809 switch (count) {
1810 case 1:
1811 VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
1812 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
1813 break;
1814 case 2:
1815 VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
1816 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
1817 break;
1818 case 3:
1819 VIXL_ASSERT(dst3.IsNone());
1820 ldr(dst2, MemOperand(StackPointer(), 2 * size));
1821 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
1822 break;
1823 case 4:
1824 // Load the higher addresses first, then load the lower addresses and skip
1825 // the whole block in the second instruction. This allows four W registers
1826 // to be popped using sp, whilst maintaining 16-byte alignment for sp at
1827 // all times.
1828 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
1829 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
1830 break;
1831 default:
1832 VIXL_UNREACHABLE();
1833 }
1834 }
1835
1836
PrepareForPush(int count,int size)1837 void MacroAssembler::PrepareForPush(int count, int size) {
1838 if (sp.Is(StackPointer())) {
1839 // If the current stack pointer is sp, then it must be aligned to 16 bytes
1840 // on entry and the total size of the specified registers must also be a
1841 // multiple of 16 bytes.
1842 VIXL_ASSERT((count * size) % 16 == 0);
1843 } else {
1844 // Even if the current stack pointer is not the system stack pointer (sp),
1845 // the system stack pointer will still be modified in order to comply with
1846 // ABI rules about accessing memory below the system stack pointer.
1847 BumpSystemStackPointer(count * size);
1848 }
1849 }
1850
1851
PrepareForPop(int count,int size)1852 void MacroAssembler::PrepareForPop(int count, int size) {
1853 USE(count, size);
1854 if (sp.Is(StackPointer())) {
1855 // If the current stack pointer is sp, then it must be aligned to 16 bytes
1856 // on entry and the total size of the specified registers must also be a
1857 // multiple of 16 bytes.
1858 VIXL_ASSERT((count * size) % 16 == 0);
1859 }
1860 }
1861
Poke(const Register & src,const Operand & offset)1862 void MacroAssembler::Poke(const Register& src, const Operand& offset) {
1863 VIXL_ASSERT(allow_macro_instructions_);
1864 if (offset.IsImmediate()) {
1865 VIXL_ASSERT(offset.immediate() >= 0);
1866 }
1867
1868 Str(src, MemOperand(StackPointer(), offset));
1869 }
1870
1871
Peek(const Register & dst,const Operand & offset)1872 void MacroAssembler::Peek(const Register& dst, const Operand& offset) {
1873 VIXL_ASSERT(allow_macro_instructions_);
1874 if (offset.IsImmediate()) {
1875 VIXL_ASSERT(offset.immediate() >= 0);
1876 }
1877
1878 Ldr(dst, MemOperand(StackPointer(), offset));
1879 }
1880
1881
Claim(const Operand & size)1882 void MacroAssembler::Claim(const Operand& size) {
1883 VIXL_ASSERT(allow_macro_instructions_);
1884
1885 if (size.IsZero()) {
1886 return;
1887 }
1888
1889 if (size.IsImmediate()) {
1890 VIXL_ASSERT(size.immediate() > 0);
1891 if (sp.Is(StackPointer())) {
1892 VIXL_ASSERT((size.immediate() % 16) == 0);
1893 }
1894 }
1895
1896 if (!sp.Is(StackPointer())) {
1897 BumpSystemStackPointer(size);
1898 }
1899
1900 Sub(StackPointer(), StackPointer(), size);
1901 }
1902
1903
Drop(const Operand & size)1904 void MacroAssembler::Drop(const Operand& size) {
1905 VIXL_ASSERT(allow_macro_instructions_);
1906
1907 if (size.IsZero()) {
1908 return;
1909 }
1910
1911 if (size.IsImmediate()) {
1912 VIXL_ASSERT(size.immediate() > 0);
1913 if (sp.Is(StackPointer())) {
1914 VIXL_ASSERT((size.immediate() % 16) == 0);
1915 }
1916 }
1917
1918 Add(StackPointer(), StackPointer(), size);
1919 }
1920
1921
PushCalleeSavedRegisters()1922 void MacroAssembler::PushCalleeSavedRegisters() {
1923 // Ensure that the macro-assembler doesn't use any scratch registers.
1924 // 10 stp will be emitted.
1925 // TODO(all): Should we use GetCalleeSaved and SavedFP.
1926 InstructionAccurateScope scope(this, 10);
1927
1928 // This method must not be called unless the current stack pointer is sp.
1929 VIXL_ASSERT(sp.Is(StackPointer()));
1930
1931 MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);
1932
1933 stp(x29, x30, tos);
1934 stp(x27, x28, tos);
1935 stp(x25, x26, tos);
1936 stp(x23, x24, tos);
1937 stp(x21, x22, tos);
1938 stp(x19, x20, tos);
1939
1940 stp(d14, d15, tos);
1941 stp(d12, d13, tos);
1942 stp(d10, d11, tos);
1943 stp(d8, d9, tos);
1944 }
1945
1946
PopCalleeSavedRegisters()1947 void MacroAssembler::PopCalleeSavedRegisters() {
1948 // Ensure that the macro-assembler doesn't use any scratch registers.
1949 // 10 ldp will be emitted.
1950 // TODO(all): Should we use GetCalleeSaved and SavedFP.
1951 InstructionAccurateScope scope(this, 10);
1952
1953 // This method must not be called unless the current stack pointer is sp.
1954 VIXL_ASSERT(sp.Is(StackPointer()));
1955
1956 MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
1957
1958 ldp(d8, d9, tos);
1959 ldp(d10, d11, tos);
1960 ldp(d12, d13, tos);
1961 ldp(d14, d15, tos);
1962
1963 ldp(x19, x20, tos);
1964 ldp(x21, x22, tos);
1965 ldp(x23, x24, tos);
1966 ldp(x25, x26, tos);
1967 ldp(x27, x28, tos);
1968 ldp(x29, x30, tos);
1969 }
1970
LoadCPURegList(CPURegList registers,const MemOperand & src)1971 void MacroAssembler::LoadCPURegList(CPURegList registers,
1972 const MemOperand& src) {
1973 LoadStoreCPURegListHelper(kLoad, registers, src);
1974 }
1975
StoreCPURegList(CPURegList registers,const MemOperand & dst)1976 void MacroAssembler::StoreCPURegList(CPURegList registers,
1977 const MemOperand& dst) {
1978 LoadStoreCPURegListHelper(kStore, registers, dst);
1979 }
1980
1981
LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,CPURegList registers,const MemOperand & mem)1982 void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
1983 CPURegList registers,
1984 const MemOperand& mem) {
1985 // We do not handle pre-indexing or post-indexing.
1986 VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
1987 VIXL_ASSERT(!registers.Overlaps(tmp_list_));
1988 VIXL_ASSERT(!registers.Overlaps(fptmp_list_));
1989 VIXL_ASSERT(!registers.IncludesAliasOf(sp));
1990
1991 UseScratchRegisterScope temps(this);
1992
1993 MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers,
1994 mem,
1995 &temps);
1996
1997 while (registers.Count() >= 2) {
1998 const CPURegister& dst0 = registers.PopLowestIndex();
1999 const CPURegister& dst1 = registers.PopLowestIndex();
2000 if (op == kStore) {
2001 Stp(dst0, dst1, loc);
2002 } else {
2003 VIXL_ASSERT(op == kLoad);
2004 Ldp(dst0, dst1, loc);
2005 }
2006 loc.AddOffset(2 * registers.RegisterSizeInBytes());
2007 }
2008 if (!registers.IsEmpty()) {
2009 if (op == kStore) {
2010 Str(registers.PopLowestIndex(), loc);
2011 } else {
2012 VIXL_ASSERT(op == kLoad);
2013 Ldr(registers.PopLowestIndex(), loc);
2014 }
2015 }
2016 }
2017
BaseMemOperandForLoadStoreCPURegList(const CPURegList & registers,const MemOperand & mem,UseScratchRegisterScope * scratch_scope)2018 MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
2019 const CPURegList& registers,
2020 const MemOperand& mem,
2021 UseScratchRegisterScope* scratch_scope) {
2022 // If necessary, pre-compute the base address for the accesses.
2023 if (mem.IsRegisterOffset()) {
2024 Register reg_base = scratch_scope->AcquireX();
2025 ComputeAddress(reg_base, mem);
2026 return MemOperand(reg_base);
2027
2028 } else if (mem.IsImmediateOffset()) {
2029 int reg_size = registers.RegisterSizeInBytes();
2030 int total_size = registers.TotalSizeInBytes();
2031 int64_t min_offset = mem.offset();
2032 int64_t max_offset = mem.offset() + std::max(0, total_size - 2 * reg_size);
2033 if ((registers.Count() >= 2) &&
2034 (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
2035 !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
2036 Register reg_base = scratch_scope->AcquireX();
2037 ComputeAddress(reg_base, mem);
2038 return MemOperand(reg_base);
2039 }
2040 }
2041
2042 return mem;
2043 }
2044
BumpSystemStackPointer(const Operand & space)2045 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
2046 VIXL_ASSERT(!sp.Is(StackPointer()));
2047 // TODO: Several callers rely on this not using scratch registers, so we use
2048 // the assembler directly here. However, this means that large immediate
2049 // values of 'space' cannot be handled.
2050 InstructionAccurateScope scope(this, 1);
2051 sub(sp, StackPointer(), space);
2052 }
2053
2054
2055 // TODO(all): Fix printf for NEON registers, and resolve whether we should be
2056 // using FPRegister or VRegister here.
2057
2058 // This is the main Printf implementation. All callee-saved registers are
2059 // 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)2060 void MacroAssembler::PrintfNoPreserve(const char * format,
2061 const CPURegister& arg0,
2062 const CPURegister& arg1,
2063 const CPURegister& arg2,
2064 const CPURegister& arg3) {
2065 // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2066 // in most cases anyway, so this restriction shouldn't be too serious.
2067 VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
2068
2069 // The provided arguments, and their proper PCS registers.
2070 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
2071 CPURegister pcs[kPrintfMaxArgCount];
2072
2073 int arg_count = kPrintfMaxArgCount;
2074
2075 // The PCS varargs registers for printf. Note that x0 is used for the printf
2076 // format string.
2077 static const CPURegList kPCSVarargs =
2078 CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
2079 static const CPURegList kPCSVarargsFP =
2080 CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
2081
2082 // We can use caller-saved registers as scratch values, except for the
2083 // arguments and the PCS registers where they might need to go.
2084 UseScratchRegisterScope temps(this);
2085 temps.Include(kCallerSaved);
2086 temps.Include(kCallerSavedV);
2087 temps.Exclude(kPCSVarargs);
2088 temps.Exclude(kPCSVarargsFP);
2089 temps.Exclude(arg0, arg1, arg2, arg3);
2090
2091 // Copies of the arg lists that we can iterate through.
2092 CPURegList pcs_varargs = kPCSVarargs;
2093 CPURegList pcs_varargs_fp = kPCSVarargsFP;
2094
2095 // Place the arguments. There are lots of clever tricks and optimizations we
2096 // could use here, but Printf is a debug tool so instead we just try to keep
2097 // it simple: Move each input that isn't already in the right place to a
2098 // scratch register, then move everything back.
2099 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
2100 // Work out the proper PCS register for this argument.
2101 if (args[i].IsRegister()) {
2102 pcs[i] = pcs_varargs.PopLowestIndex().X();
2103 // We might only need a W register here. We need to know the size of the
2104 // argument so we can properly encode it for the simulator call.
2105 if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
2106 } else if (args[i].IsVRegister()) {
2107 // In C, floats are always cast to doubles for varargs calls.
2108 pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
2109 } else {
2110 VIXL_ASSERT(args[i].IsNone());
2111 arg_count = i;
2112 break;
2113 }
2114
2115 // If the argument is already in the right place, leave it where it is.
2116 if (args[i].Aliases(pcs[i])) continue;
2117
2118 // Otherwise, if the argument is in a PCS argument register, allocate an
2119 // appropriate scratch register and then move it out of the way.
2120 if (kPCSVarargs.IncludesAliasOf(args[i]) ||
2121 kPCSVarargsFP.IncludesAliasOf(args[i])) {
2122 if (args[i].IsRegister()) {
2123 Register old_arg = Register(args[i]);
2124 Register new_arg = temps.AcquireSameSizeAs(old_arg);
2125 Mov(new_arg, old_arg);
2126 args[i] = new_arg;
2127 } else {
2128 FPRegister old_arg = FPRegister(args[i]);
2129 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
2130 Fmov(new_arg, old_arg);
2131 args[i] = new_arg;
2132 }
2133 }
2134 }
2135
2136 // Do a second pass to move values into their final positions and perform any
2137 // conversions that may be required.
2138 for (int i = 0; i < arg_count; i++) {
2139 VIXL_ASSERT(pcs[i].type() == args[i].type());
2140 if (pcs[i].IsRegister()) {
2141 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2142 } else {
2143 VIXL_ASSERT(pcs[i].IsVRegister());
2144 if (pcs[i].size() == args[i].size()) {
2145 Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
2146 } else {
2147 Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
2148 }
2149 }
2150 }
2151
2152 // Load the format string into x0, as per the procedure-call standard.
2153 //
2154 // To make the code as portable as possible, the format string is encoded
2155 // directly in the instruction stream. It might be cleaner to encode it in a
2156 // literal pool, but since Printf is usually used for debugging, it is
2157 // beneficial for it to be minimally dependent on other features.
2158 temps.Exclude(x0);
2159 Label format_address;
2160 Adr(x0, &format_address);
2161
2162 // Emit the format string directly in the instruction stream.
2163 {
2164 BlockPoolsScope scope(this);
2165 // Data emitted:
2166 // branch
2167 // strlen(format) + 1 (includes null termination)
2168 // padding to next instruction
2169 // unreachable
2170 EmissionCheckScope guard(
2171 this,
2172 AlignUp(strlen(format) + 1, kInstructionSize) + 2 * kInstructionSize);
2173 Label after_data;
2174 B(&after_data);
2175 Bind(&format_address);
2176 EmitString(format);
2177 Unreachable();
2178 Bind(&after_data);
2179 }
2180
2181 // We don't pass any arguments on the stack, but we still need to align the C
2182 // stack pointer to a 16-byte boundary for PCS compliance.
2183 if (!sp.Is(StackPointer())) {
2184 Bic(sp, StackPointer(), 0xf);
2185 }
2186
2187 // Actually call printf. This part needs special handling for the simulator,
2188 // since the system printf function will use a different instruction set and
2189 // the procedure-call standard will not be compatible.
2190 if (allow_simulator_instructions_) {
2191 InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
2192 hlt(kPrintfOpcode);
2193 dc32(arg_count); // kPrintfArgCountOffset
2194
2195 // Determine the argument pattern.
2196 uint32_t arg_pattern_list = 0;
2197 for (int i = 0; i < arg_count; i++) {
2198 uint32_t arg_pattern;
2199 if (pcs[i].IsRegister()) {
2200 arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
2201 } else {
2202 VIXL_ASSERT(pcs[i].Is64Bits());
2203 arg_pattern = kPrintfArgD;
2204 }
2205 VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
2206 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
2207 }
2208 dc32(arg_pattern_list); // kPrintfArgPatternListOffset
2209 } else {
2210 Register tmp = temps.AcquireX();
2211 Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2212 Blr(tmp);
2213 }
2214 }
2215
2216
Printf(const char * format,CPURegister arg0,CPURegister arg1,CPURegister arg2,CPURegister arg3)2217 void MacroAssembler::Printf(const char * format,
2218 CPURegister arg0,
2219 CPURegister arg1,
2220 CPURegister arg2,
2221 CPURegister arg3) {
2222 // We can only print sp if it is the current stack pointer.
2223 if (!sp.Is(StackPointer())) {
2224 VIXL_ASSERT(!sp.Aliases(arg0));
2225 VIXL_ASSERT(!sp.Aliases(arg1));
2226 VIXL_ASSERT(!sp.Aliases(arg2));
2227 VIXL_ASSERT(!sp.Aliases(arg3));
2228 }
2229
2230 // Make sure that the macro assembler doesn't try to use any of our arguments
2231 // as scratch registers.
2232 UseScratchRegisterScope exclude_all(this);
2233 exclude_all.ExcludeAll();
2234
2235 // Preserve all caller-saved registers as well as NZCV.
2236 // If sp is the stack pointer, PushCPURegList asserts that the size of each
2237 // list is a multiple of 16 bytes.
2238 PushCPURegList(kCallerSaved);
2239 PushCPURegList(kCallerSavedV);
2240
2241 { UseScratchRegisterScope temps(this);
2242 // We can use caller-saved registers as scratch values (except for argN).
2243 temps.Include(kCallerSaved);
2244 temps.Include(kCallerSavedV);
2245 temps.Exclude(arg0, arg1, arg2, arg3);
2246
2247 // If any of the arguments are the current stack pointer, allocate a new
2248 // register for them, and adjust the value to compensate for pushing the
2249 // caller-saved registers.
2250 bool arg0_sp = StackPointer().Aliases(arg0);
2251 bool arg1_sp = StackPointer().Aliases(arg1);
2252 bool arg2_sp = StackPointer().Aliases(arg2);
2253 bool arg3_sp = StackPointer().Aliases(arg3);
2254 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
2255 // Allocate a register to hold the original stack pointer value, to pass
2256 // to PrintfNoPreserve as an argument.
2257 Register arg_sp = temps.AcquireX();
2258 Add(arg_sp, StackPointer(),
2259 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes());
2260 if (arg0_sp) arg0 = Register(arg_sp.code(), arg0.size());
2261 if (arg1_sp) arg1 = Register(arg_sp.code(), arg1.size());
2262 if (arg2_sp) arg2 = Register(arg_sp.code(), arg2.size());
2263 if (arg3_sp) arg3 = Register(arg_sp.code(), arg3.size());
2264 }
2265
2266 // Preserve NZCV.
2267 Register tmp = temps.AcquireX();
2268 Mrs(tmp, NZCV);
2269 Push(tmp, xzr);
2270 temps.Release(tmp);
2271
2272 PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2273
2274 // Restore NZCV.
2275 tmp = temps.AcquireX();
2276 Pop(xzr, tmp);
2277 Msr(NZCV, tmp);
2278 temps.Release(tmp);
2279 }
2280
2281 PopCPURegList(kCallerSavedV);
2282 PopCPURegList(kCallerSaved);
2283 }
2284
Trace(TraceParameters parameters,TraceCommand command)2285 void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
2286 VIXL_ASSERT(allow_macro_instructions_);
2287
2288 if (allow_simulator_instructions_) {
2289 // The arguments to the trace pseudo instruction need to be contiguous in
2290 // memory, so make sure we don't try to emit a literal pool.
2291 InstructionAccurateScope scope(this, kTraceLength / kInstructionSize);
2292
2293 Label start;
2294 bind(&start);
2295
2296 // Refer to simulator-a64.h for a description of the marker and its
2297 // arguments.
2298 hlt(kTraceOpcode);
2299
2300 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2301 dc32(parameters);
2302
2303 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2304 dc32(command);
2305 } else {
2306 // Emit nothing on real hardware.
2307 USE(parameters, command);
2308 }
2309 }
2310
2311
Log(TraceParameters parameters)2312 void MacroAssembler::Log(TraceParameters parameters) {
2313 VIXL_ASSERT(allow_macro_instructions_);
2314
2315 if (allow_simulator_instructions_) {
2316 // The arguments to the log pseudo instruction need to be contiguous in
2317 // memory, so make sure we don't try to emit a literal pool.
2318 InstructionAccurateScope scope(this, kLogLength / kInstructionSize);
2319
2320 Label start;
2321 bind(&start);
2322
2323 // Refer to simulator-a64.h for a description of the marker and its
2324 // arguments.
2325 hlt(kLogOpcode);
2326
2327 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2328 dc32(parameters);
2329 } else {
2330 // Emit nothing on real hardware.
2331 USE(parameters);
2332 }
2333 }
2334
2335
EnableInstrumentation()2336 void MacroAssembler::EnableInstrumentation() {
2337 VIXL_ASSERT(!isprint(InstrumentStateEnable));
2338 InstructionAccurateScope scope(this, 1);
2339 movn(xzr, InstrumentStateEnable);
2340 }
2341
2342
DisableInstrumentation()2343 void MacroAssembler::DisableInstrumentation() {
2344 VIXL_ASSERT(!isprint(InstrumentStateDisable));
2345 InstructionAccurateScope scope(this, 1);
2346 movn(xzr, InstrumentStateDisable);
2347 }
2348
2349
AnnotateInstrumentation(const char * marker_name)2350 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
2351 VIXL_ASSERT(strlen(marker_name) == 2);
2352
2353 // We allow only printable characters in the marker names. Unprintable
2354 // characters are reserved for controlling features of the instrumentation.
2355 VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
2356
2357 InstructionAccurateScope scope(this, 1);
2358 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
2359 }
2360
2361
Open(MacroAssembler * masm)2362 void UseScratchRegisterScope::Open(MacroAssembler* masm) {
2363 VIXL_ASSERT(!initialised_);
2364 available_ = masm->TmpList();
2365 availablefp_ = masm->FPTmpList();
2366 old_available_ = available_->list();
2367 old_availablefp_ = availablefp_->list();
2368 VIXL_ASSERT(available_->type() == CPURegister::kRegister);
2369 VIXL_ASSERT(availablefp_->type() == CPURegister::kVRegister);
2370 #ifdef VIXL_DEBUG
2371 initialised_ = true;
2372 #endif
2373 }
2374
2375
Close()2376 void UseScratchRegisterScope::Close() {
2377 if (available_) {
2378 available_->set_list(old_available_);
2379 available_ = NULL;
2380 }
2381 if (availablefp_) {
2382 availablefp_->set_list(old_availablefp_);
2383 availablefp_ = NULL;
2384 }
2385 #ifdef VIXL_DEBUG
2386 initialised_ = false;
2387 #endif
2388 }
2389
2390
UseScratchRegisterScope(MacroAssembler * masm)2391 UseScratchRegisterScope::UseScratchRegisterScope(MacroAssembler* masm) {
2392 #ifdef VIXL_DEBUG
2393 initialised_ = false;
2394 #endif
2395 Open(masm);
2396 }
2397
2398 // This allows deferred (and optional) initialisation of the scope.
UseScratchRegisterScope()2399 UseScratchRegisterScope::UseScratchRegisterScope()
2400 : available_(NULL), availablefp_(NULL),
2401 old_available_(0), old_availablefp_(0) {
2402 #ifdef VIXL_DEBUG
2403 initialised_ = false;
2404 #endif
2405 }
2406
~UseScratchRegisterScope()2407 UseScratchRegisterScope::~UseScratchRegisterScope() {
2408 Close();
2409 }
2410
2411
IsAvailable(const CPURegister & reg) const2412 bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2413 return available_->IncludesAliasOf(reg) || availablefp_->IncludesAliasOf(reg);
2414 }
2415
2416
AcquireSameSizeAs(const Register & reg)2417 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
2418 int code = AcquireNextAvailable(available_).code();
2419 return Register(code, reg.size());
2420 }
2421
2422
AcquireSameSizeAs(const FPRegister & reg)2423 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
2424 int code = AcquireNextAvailable(availablefp_).code();
2425 return FPRegister(code, reg.size());
2426 }
2427
2428
Release(const CPURegister & reg)2429 void UseScratchRegisterScope::Release(const CPURegister& reg) {
2430 VIXL_ASSERT(initialised_);
2431 if (reg.IsRegister()) {
2432 ReleaseByCode(available_, reg.code());
2433 } else if (reg.IsFPRegister()) {
2434 ReleaseByCode(availablefp_, reg.code());
2435 } else {
2436 VIXL_ASSERT(reg.IsNone());
2437 }
2438 }
2439
2440
Include(const CPURegList & list)2441 void UseScratchRegisterScope::Include(const CPURegList& list) {
2442 VIXL_ASSERT(initialised_);
2443 if (list.type() == CPURegister::kRegister) {
2444 // Make sure that neither sp nor xzr are included the list.
2445 IncludeByRegList(available_, list.list() & ~(xzr.Bit() | sp.Bit()));
2446 } else {
2447 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
2448 IncludeByRegList(availablefp_, list.list());
2449 }
2450 }
2451
2452
Include(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)2453 void UseScratchRegisterScope::Include(const Register& reg1,
2454 const Register& reg2,
2455 const Register& reg3,
2456 const Register& reg4) {
2457 VIXL_ASSERT(initialised_);
2458 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2459 // Make sure that neither sp nor xzr are included the list.
2460 include &= ~(xzr.Bit() | sp.Bit());
2461
2462 IncludeByRegList(available_, include);
2463 }
2464
2465
Include(const FPRegister & reg1,const FPRegister & reg2,const FPRegister & reg3,const FPRegister & reg4)2466 void UseScratchRegisterScope::Include(const FPRegister& reg1,
2467 const FPRegister& reg2,
2468 const FPRegister& reg3,
2469 const FPRegister& reg4) {
2470 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2471 IncludeByRegList(availablefp_, include);
2472 }
2473
2474
Exclude(const CPURegList & list)2475 void UseScratchRegisterScope::Exclude(const CPURegList& list) {
2476 if (list.type() == CPURegister::kRegister) {
2477 ExcludeByRegList(available_, list.list());
2478 } else {
2479 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
2480 ExcludeByRegList(availablefp_, list.list());
2481 }
2482 }
2483
2484
Exclude(const Register & reg1,const Register & reg2,const Register & reg3,const Register & reg4)2485 void UseScratchRegisterScope::Exclude(const Register& reg1,
2486 const Register& reg2,
2487 const Register& reg3,
2488 const Register& reg4) {
2489 RegList exclude = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2490 ExcludeByRegList(available_, exclude);
2491 }
2492
2493
Exclude(const FPRegister & reg1,const FPRegister & reg2,const FPRegister & reg3,const FPRegister & reg4)2494 void UseScratchRegisterScope::Exclude(const FPRegister& reg1,
2495 const FPRegister& reg2,
2496 const FPRegister& reg3,
2497 const FPRegister& reg4) {
2498 RegList excludefp = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2499 ExcludeByRegList(availablefp_, excludefp);
2500 }
2501
2502
Exclude(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)2503 void UseScratchRegisterScope::Exclude(const CPURegister& reg1,
2504 const CPURegister& reg2,
2505 const CPURegister& reg3,
2506 const CPURegister& reg4) {
2507 RegList exclude = 0;
2508 RegList excludefp = 0;
2509
2510 const CPURegister regs[] = {reg1, reg2, reg3, reg4};
2511
2512 for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
2513 if (regs[i].IsRegister()) {
2514 exclude |= regs[i].Bit();
2515 } else if (regs[i].IsFPRegister()) {
2516 excludefp |= regs[i].Bit();
2517 } else {
2518 VIXL_ASSERT(regs[i].IsNone());
2519 }
2520 }
2521
2522 ExcludeByRegList(available_, exclude);
2523 ExcludeByRegList(availablefp_, excludefp);
2524 }
2525
2526
ExcludeAll()2527 void UseScratchRegisterScope::ExcludeAll() {
2528 ExcludeByRegList(available_, available_->list());
2529 ExcludeByRegList(availablefp_, availablefp_->list());
2530 }
2531
2532
AcquireNextAvailable(CPURegList * available)2533 CPURegister UseScratchRegisterScope::AcquireNextAvailable(
2534 CPURegList* available) {
2535 VIXL_CHECK(!available->IsEmpty());
2536 CPURegister result = available->PopLowestIndex();
2537 VIXL_ASSERT(!AreAliased(result, xzr, sp));
2538 return result;
2539 }
2540
2541
ReleaseByCode(CPURegList * available,int code)2542 void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
2543 ReleaseByRegList(available, static_cast<RegList>(1) << code);
2544 }
2545
2546
ReleaseByRegList(CPURegList * available,RegList regs)2547 void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
2548 RegList regs) {
2549 available->set_list(available->list() | regs);
2550 }
2551
2552
IncludeByRegList(CPURegList * available,RegList regs)2553 void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
2554 RegList regs) {
2555 available->set_list(available->list() | regs);
2556 }
2557
2558
ExcludeByRegList(CPURegList * available,RegList exclude)2559 void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
2560 RegList exclude) {
2561 available->set_list(available->list() & ~exclude);
2562 }
2563
2564 } // namespace vixl
2565