blob: d26d2a202a81bd995910acd094ba9ce343946904 [file] [log] [blame]
armvixl5289c592015-03-02 13:52:04 +00001// Copyright 2015, ARM Limited
armvixlad96eda2013-06-14 11:42:37 +01002// 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
armvixl684cd2a2015-10-23 13:38:33 +010027#include <ctype.h>
28
Alexandre Rames39c32a62016-05-23 15:47:22 +010029#include "a64/macro-assembler-a64.h"
armvixl5289c592015-03-02 13:52:04 +000030
armvixlad96eda2013-06-14 11:42:37 +010031namespace vixl {
32
armvixlc68cb642014-09-25 18:49:30 +010033
armvixl5289c592015-03-02 13:52:04 +000034void 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
42void Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {
43 masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);
44 checkpoint_ = checkpoint;
45}
46
47
armvixl6e2c8272015-03-31 11:04:14 +010048LiteralPool::LiteralPool(MacroAssembler* masm)
armvixl0f35e362016-05-10 13:57:58 +010049 : Pool(masm),
50 size_(0),
51 first_use_(-1),
52 recommended_checkpoint_(kNoCheckpointRequired) {}
armvixlc68cb642014-09-25 18:49:30 +010053
54
55LiteralPool::~LiteralPool() {
56 VIXL_ASSERT(IsEmpty());
57 VIXL_ASSERT(!IsBlocked());
armvixldb644342015-07-21 11:37:10 +010058 for (std::vector<RawLiteral*>::iterator it = deleted_on_destruction_.begin();
59 it != deleted_on_destruction_.end();
60 it++) {
61 delete *it;
62 }
armvixlc68cb642014-09-25 18:49:30 +010063}
64
65
66void LiteralPool::Reset() {
67 std::vector<RawLiteral*>::iterator it, end;
68 for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
armvixldb644342015-07-21 11:37:10 +010069 RawLiteral* literal = *it;
70 if (literal->deletion_policy_ == RawLiteral::kDeletedOnPlacementByPool) {
71 delete literal;
72 }
armvixlc68cb642014-09-25 18:49:30 +010073 }
74 entries_.clear();
armvixl5289c592015-03-02 13:52:04 +000075 size_ = 0;
armvixlc68cb642014-09-25 18:49:30 +010076 first_use_ = -1;
armvixl5289c592015-03-02 13:52:04 +000077 Pool::Reset();
78 recommended_checkpoint_ = kNoCheckpointRequired;
armvixlc68cb642014-09-25 18:49:30 +010079}
80
81
82void LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {
83 if (IsEmpty() || IsBlocked()) return;
84
armvixl5289c592015-03-02 13:52:04 +000085 ptrdiff_t distance = masm_->CursorOffset() + amount - first_use_;
armvixlc68cb642014-09-25 18:49:30 +010086 if (distance >= kRecommendedLiteralPoolRange) {
87 Emit(option);
88 }
89}
90
91
92void LiteralPool::Emit(EmitOption option) {
93 // There is an issue if we are asked to emit a blocked or empty pool.
94 VIXL_ASSERT(!IsBlocked());
95 VIXL_ASSERT(!IsEmpty());
96
97 size_t pool_size = Size();
98 size_t emit_size = pool_size;
99 if (option == kBranchRequired) emit_size += kInstructionSize;
100 Label end_of_pool;
101
armvixl5289c592015-03-02 13:52:04 +0000102 VIXL_ASSERT(emit_size % kInstructionSize == 0);
103 InstructionAccurateScope guard(masm_, emit_size / kInstructionSize);
104 if (option == kBranchRequired) masm_->b(&end_of_pool);
armvixlc68cb642014-09-25 18:49:30 +0100105
106 // Marker indicating the size of the literal pool in 32-bit words.
107 VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);
armvixldb644342015-07-21 11:37:10 +0100108 masm_->ldr(xzr, static_cast<int>(pool_size / kWRegSizeInBytes));
armvixlc68cb642014-09-25 18:49:30 +0100109
110 // Now populate the literal pool.
111 std::vector<RawLiteral*>::iterator it, end;
112 for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
113 VIXL_ASSERT((*it)->IsUsed());
armvixl5289c592015-03-02 13:52:04 +0000114 masm_->place(*it);
armvixlc68cb642014-09-25 18:49:30 +0100115 }
116
armvixl5289c592015-03-02 13:52:04 +0000117 if (option == kBranchRequired) masm_->bind(&end_of_pool);
armvixlc68cb642014-09-25 18:49:30 +0100118
armvixl5289c592015-03-02 13:52:04 +0000119 Reset();
armvixlc68cb642014-09-25 18:49:30 +0100120}
121
122
armvixldb644342015-07-21 11:37:10 +0100123void LiteralPool::AddEntry(RawLiteral* literal) {
124 // A literal must be registered immediately before its first use. Here we
125 // cannot control that it is its first use, but we check no code has been
126 // emitted since its last use.
127 VIXL_ASSERT(masm_->CursorOffset() == literal->last_use());
128
129 UpdateFirstUse(masm_->CursorOffset());
130 VIXL_ASSERT(masm_->CursorOffset() >= first_use_);
131 entries_.push_back(literal);
132 size_ += literal->size();
133}
134
135
136void LiteralPool::UpdateFirstUse(ptrdiff_t use_position) {
137 first_use_ = std::min(first_use_, use_position);
138 if (first_use_ == -1) {
139 first_use_ = use_position;
armvixl5289c592015-03-02 13:52:04 +0000140 SetNextRecommendedCheckpoint(NextRecommendedCheckpoint());
141 SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);
142 } else {
armvixldb644342015-07-21 11:37:10 +0100143 VIXL_ASSERT(use_position > first_use_);
armvixlc68cb642014-09-25 18:49:30 +0100144 }
armvixl5289c592015-03-02 13:52:04 +0000145}
146
147
148void VeneerPool::Reset() {
149 Pool::Reset();
150 unresolved_branches_.Reset();
151}
152
153
154void VeneerPool::Release() {
155 if (--monitor_ == 0) {
156 VIXL_ASSERT(IsEmpty() ||
157 masm_->CursorOffset() < unresolved_branches_.FirstLimit());
158 }
159}
160
161
162void VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,
163 Label* label,
164 ImmBranchType branch_type) {
165 VIXL_ASSERT(!label->IsBound());
166 BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);
167 unresolved_branches_.insert(branch_info);
168 UpdateNextCheckPoint();
169 // TODO: In debug mode register the label with the assembler to make sure it
170 // is bound with masm Bind and not asm bind.
171}
172
173
174void VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {
175 if (IsEmpty()) {
176 VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);
177 return;
178 }
179
180 if (label->IsLinked()) {
181 Label::LabelLinksIterator links_it(label);
182 for (; !links_it.Done(); links_it.Advance()) {
183 ptrdiff_t link_offset = *links_it.Current();
184 Instruction* link = masm_->InstructionAt(link_offset);
185
186 // ADR instructions are not handled.
187 if (BranchTypeUsesVeneers(link->BranchType())) {
188 BranchInfo branch_info(link_offset, label, link->BranchType());
189 unresolved_branches_.erase(branch_info);
190 }
191 }
192 }
193
194 UpdateNextCheckPoint();
195}
196
197
armvixldb644342015-07-21 11:37:10 +0100198bool VeneerPool::ShouldEmitVeneer(int64_t max_reachable_pc, size_t amount) {
armvixl5289c592015-03-02 13:52:04 +0000199 ptrdiff_t offset =
200 kPoolNonVeneerCodeSize + amount + MaxSize() + OtherPoolsMaxSize();
201 return (masm_->CursorOffset() + offset) > max_reachable_pc;
202}
203
204
205void VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {
206 if (IsEmpty()) return;
207
208 VIXL_ASSERT(masm_->CursorOffset() < unresolved_branches_.FirstLimit());
209
210 if (IsBlocked()) return;
211
212 if (ShouldEmitVeneers(amount)) {
213 Emit(option, amount);
214 } else {
215 UpdateNextCheckPoint();
216 }
217}
218
219
220void VeneerPool::Emit(EmitOption option, size_t amount) {
221 // There is an issue if we are asked to emit a blocked or empty pool.
222 VIXL_ASSERT(!IsBlocked());
223 VIXL_ASSERT(!IsEmpty());
224
225 Label end;
226 if (option == kBranchRequired) {
227 InstructionAccurateScope scope(masm_, 1);
228 masm_->b(&end);
229 }
230
231 // We want to avoid generating veneer pools too often, so generate veneers for
232 // branches that don't immediately require a veneer but will soon go out of
233 // range.
234 static const size_t kVeneerEmissionMargin = 1 * KBytes;
235
236 for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {
237 BranchInfo* branch_info = it.Current();
238 if (ShouldEmitVeneer(branch_info->max_reachable_pc_,
239 amount + kVeneerEmissionMargin)) {
240 InstructionAccurateScope scope(masm_, kVeneerCodeSize / kInstructionSize);
241 ptrdiff_t branch_pos = branch_info->pc_offset_;
242 Instruction* branch = masm_->InstructionAt(branch_pos);
243 Label* label = branch_info->label_;
244
245 // Patch the branch to point to the current position, and emit a branch
246 // to the label.
247 Instruction* veneer = masm_->GetCursorAddress<Instruction*>();
248 branch->SetImmPCOffsetTarget(veneer);
249 masm_->b(label);
250
251 // Update the label. The branch patched does not point to it any longer.
252 label->DeleteLink(branch_pos);
253
254 it.DeleteCurrentAndAdvance();
255 } else {
256 it.AdvanceToNextType();
257 }
258 }
259
260 UpdateNextCheckPoint();
261
262 masm_->bind(&end);
armvixlc68cb642014-09-25 18:49:30 +0100263}
264
265
armvixldb644342015-07-21 11:37:10 +0100266EmissionCheckScope::EmissionCheckScope(MacroAssembler* masm, size_t size)
267 : masm_(masm) {
armvixl0f35e362016-05-10 13:57:58 +0100268 if (masm_ == NULL) {
269 // Nothing to do.
270 // We may reach this point in a context of conditional code generation. See
271 // `MacroAssembler::MoveImmediateHelper()` for an example.
272 return;
273 }
armvixldb644342015-07-21 11:37:10 +0100274 masm_->EnsureEmitFor(size);
275 masm_->BlockPools();
armvixl330dc712014-11-25 10:38:32 +0000276#ifdef VIXL_DEBUG
armvixldb644342015-07-21 11:37:10 +0100277 masm_->Bind(&start_);
278 size_ = size;
279 masm_->AcquireBuffer();
armvixlc68cb642014-09-25 18:49:30 +0100280#endif
281}
282
283
284EmissionCheckScope::~EmissionCheckScope() {
armvixl0f35e362016-05-10 13:57:58 +0100285 if (masm_ == NULL) {
286 // Nothing to do.
287 return;
288 }
armvixl330dc712014-11-25 10:38:32 +0000289#ifdef VIXL_DEBUG
armvixldb644342015-07-21 11:37:10 +0100290 masm_->ReleaseBuffer();
291 VIXL_ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) <= size_);
armvixlc68cb642014-09-25 18:49:30 +0100292#endif
armvixldb644342015-07-21 11:37:10 +0100293 masm_->ReleasePools();
armvixlc68cb642014-09-25 18:49:30 +0100294}
295
296
297MacroAssembler::MacroAssembler(size_t capacity,
298 PositionIndependentCodeOption pic)
299 : Assembler(capacity, pic),
armvixl330dc712014-11-25 10:38:32 +0000300#ifdef VIXL_DEBUG
armvixlc68cb642014-09-25 18:49:30 +0100301 allow_macro_instructions_(true),
302#endif
armvixl684cd2a2015-10-23 13:38:33 +0100303 allow_simulator_instructions_(VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE),
armvixlc68cb642014-09-25 18:49:30 +0100304 sp_(sp),
305 tmp_list_(ip0, ip1),
306 fptmp_list_(d31),
armvixl5289c592015-03-02 13:52:04 +0000307 literal_pool_(this),
armvixldb644342015-07-21 11:37:10 +0100308 veneer_pool_(this),
309 recommended_checkpoint_(Pool::kNoCheckpointRequired) {
armvixl5289c592015-03-02 13:52:04 +0000310 checkpoint_ = NextCheckPoint();
armvixlc68cb642014-09-25 18:49:30 +0100311}
312
313
armvixl0f35e362016-05-10 13:57:58 +0100314MacroAssembler::MacroAssembler(byte* buffer,
armvixlc68cb642014-09-25 18:49:30 +0100315 size_t capacity,
316 PositionIndependentCodeOption pic)
317 : Assembler(buffer, capacity, pic),
armvixl330dc712014-11-25 10:38:32 +0000318#ifdef VIXL_DEBUG
armvixlc68cb642014-09-25 18:49:30 +0100319 allow_macro_instructions_(true),
320#endif
armvixl684cd2a2015-10-23 13:38:33 +0100321 allow_simulator_instructions_(VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE),
armvixlc68cb642014-09-25 18:49:30 +0100322 sp_(sp),
323 tmp_list_(ip0, ip1),
324 fptmp_list_(d31),
armvixl5289c592015-03-02 13:52:04 +0000325 literal_pool_(this),
armvixldb644342015-07-21 11:37:10 +0100326 veneer_pool_(this),
327 recommended_checkpoint_(Pool::kNoCheckpointRequired) {
armvixl5289c592015-03-02 13:52:04 +0000328 checkpoint_ = NextCheckPoint();
armvixlc68cb642014-09-25 18:49:30 +0100329}
330
331
armvixl0f35e362016-05-10 13:57:58 +0100332MacroAssembler::~MacroAssembler() {}
armvixlc68cb642014-09-25 18:49:30 +0100333
334
335void MacroAssembler::Reset() {
336 Assembler::Reset();
337
338 VIXL_ASSERT(!literal_pool_.IsBlocked());
339 literal_pool_.Reset();
armvixl5289c592015-03-02 13:52:04 +0000340 veneer_pool_.Reset();
armvixlc68cb642014-09-25 18:49:30 +0100341
armvixl5289c592015-03-02 13:52:04 +0000342 checkpoint_ = NextCheckPoint();
armvixlc68cb642014-09-25 18:49:30 +0100343}
344
345
346void MacroAssembler::FinalizeCode() {
347 if (!literal_pool_.IsEmpty()) literal_pool_.Emit();
armvixl5289c592015-03-02 13:52:04 +0000348 VIXL_ASSERT(veneer_pool_.IsEmpty());
armvixlc68cb642014-09-25 18:49:30 +0100349
350 Assembler::FinalizeCode();
351}
352
353
armvixl5289c592015-03-02 13:52:04 +0000354void MacroAssembler::CheckEmitFor(size_t amount) {
355 ptrdiff_t offset = amount;
356
357 literal_pool_.CheckEmitFor(amount);
358 veneer_pool_.CheckEmitFor(amount);
359 // Ensure there's enough space for the emit, keep in mind the cursor will
360 // have moved if a pool was emitted.
361 if ((CursorOffset() + offset) > BufferEndOffset()) {
362 EnsureSpaceFor(amount);
363 }
364
365 checkpoint_ = NextCheckPoint();
366}
367
368
armvixl330dc712014-11-25 10:38:32 +0000369int MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,
armvixl0f35e362016-05-10 13:57:58 +0100370 const Register& rd,
armvixl330dc712014-11-25 10:38:32 +0000371 uint64_t imm) {
372 bool emit_code = (masm != NULL);
373 VIXL_ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits());
374 // The worst case for size is mov 64-bit immediate to sp:
375 // * up to 4 instructions to materialise the constant
376 // * 1 instruction to move to sp
377 MacroEmissionCheckScope guard(masm);
378
379 // Immediates on Aarch64 can be produced using an initial value, and zero to
380 // three move keep operations.
381 //
382 // Initial values can be generated with:
383 // 1. 64-bit move zero (movz).
384 // 2. 32-bit move inverted (movn).
385 // 3. 64-bit move inverted.
386 // 4. 32-bit orr immediate.
387 // 5. 64-bit orr immediate.
388 // Move-keep may then be used to modify each of the 16-bit half words.
389 //
390 // The code below supports all five initial value generators, and
391 // applying move-keep operations to move-zero and move-inverted initial
392 // values.
393
394 // Try to move the immediate in one instruction, and if that fails, switch to
395 // using multiple instructions.
396 if (OneInstrMoveImmediateHelper(masm, rd, imm)) {
397 return 1;
398 } else {
399 int instruction_count = 0;
400 unsigned reg_size = rd.size();
401
402 // Generic immediate case. Imm will be represented by
403 // [imm3, imm2, imm1, imm0], where each imm is 16 bits.
404 // A move-zero or move-inverted is generated for the first non-zero or
405 // non-0xffff immX, and a move-keep for subsequent non-zero immX.
406
407 uint64_t ignored_halfword = 0;
408 bool invert_move = false;
409 // If the number of 0xffff halfwords is greater than the number of 0x0000
410 // halfwords, it's more efficient to use move-inverted.
411 if (CountClearHalfWords(~imm, reg_size) >
412 CountClearHalfWords(imm, reg_size)) {
413 ignored_halfword = 0xffff;
414 invert_move = true;
415 }
416
417 // Mov instructions can't move values into the stack pointer, so set up a
418 // temporary register, if needed.
419 UseScratchRegisterScope temps;
420 Register temp;
421 if (emit_code) {
422 temps.Open(masm);
423 temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
424 }
425
426 // Iterate through the halfwords. Use movn/movz for the first non-ignored
427 // halfword, and movk for subsequent halfwords.
428 VIXL_ASSERT((reg_size % 16) == 0);
429 bool first_mov_done = false;
armvixl0f35e362016-05-10 13:57:58 +0100430 for (unsigned i = 0; i < (reg_size / 16); i++) {
armvixl330dc712014-11-25 10:38:32 +0000431 uint64_t imm16 = (imm >> (16 * i)) & 0xffff;
432 if (imm16 != ignored_halfword) {
433 if (!first_mov_done) {
434 if (invert_move) {
435 if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);
436 instruction_count++;
437 } else {
438 if (emit_code) masm->movz(temp, imm16, 16 * i);
439 instruction_count++;
440 }
441 first_mov_done = true;
442 } else {
443 // Construct a wider constant.
444 if (emit_code) masm->movk(temp, imm16, 16 * i);
445 instruction_count++;
446 }
447 }
448 }
449
450 VIXL_ASSERT(first_mov_done);
451
452 // Move the temporary if the original destination register was the stack
453 // pointer.
454 if (rd.IsSP()) {
455 if (emit_code) masm->mov(rd, temp);
456 instruction_count++;
457 }
458 return instruction_count;
459 }
460}
461
462
463bool MacroAssembler::OneInstrMoveImmediateHelper(MacroAssembler* masm,
464 const Register& dst,
465 int64_t imm) {
466 bool emit_code = masm != NULL;
467 unsigned n, imm_s, imm_r;
468 int reg_size = dst.size();
469
470 if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
471 // Immediate can be represented in a move zero instruction. Movz can't write
472 // to the stack pointer.
473 if (emit_code) {
474 masm->movz(dst, imm);
475 }
476 return true;
477 } else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
478 // Immediate can be represented in a move negative instruction. Movn can't
479 // write to the stack pointer.
480 if (emit_code) {
481 masm->movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
482 }
483 return true;
484 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
485 // Immediate can be represented in a logical orr instruction.
486 VIXL_ASSERT(!dst.IsZero());
487 if (emit_code) {
armvixl0f35e362016-05-10 13:57:58 +0100488 masm->LogicalImmediate(dst,
489 AppropriateZeroRegFor(dst),
490 n,
491 imm_s,
492 imm_r,
493 ORR);
armvixl330dc712014-11-25 10:38:32 +0000494 }
495 return true;
496 }
497 return false;
498}
499
500
armvixlb0c8ae22014-03-21 14:03:59 +0000501void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
502 VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&
503 ((bit == -1) || (type >= kBranchTypeFirstUsingBit)));
504 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
505 B(static_cast<Condition>(type), label);
506 } else {
507 switch (type) {
armvixl0f35e362016-05-10 13:57:58 +0100508 case always:
509 B(label);
510 break;
511 case never:
512 break;
513 case reg_zero:
514 Cbz(reg, label);
515 break;
516 case reg_not_zero:
517 Cbnz(reg, label);
518 break;
519 case reg_bit_clear:
520 Tbz(reg, bit, label);
521 break;
522 case reg_bit_set:
523 Tbnz(reg, bit, label);
524 break;
armvixlb0c8ae22014-03-21 14:03:59 +0000525 default:
526 VIXL_UNREACHABLE();
527 }
528 }
529}
530
armvixl5289c592015-03-02 13:52:04 +0000531
532void MacroAssembler::B(Label* label) {
533 SingleEmissionCheckScope guard(this);
534 b(label);
535}
536
537
538void MacroAssembler::B(Label* label, Condition cond) {
539 VIXL_ASSERT(allow_macro_instructions_);
540 VIXL_ASSERT((cond != al) && (cond != nv));
541 EmissionCheckScope guard(this, 2 * kInstructionSize);
542
543 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
544 Label done;
545 b(&done, InvertCondition(cond));
546 b(label);
547 bind(&done);
548 } else {
549 if (!label->IsBound()) {
550 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
551 label,
552 CondBranchType);
553 }
554 b(label, cond);
555 }
556}
557
558
559void MacroAssembler::Cbnz(const Register& rt, Label* label) {
560 VIXL_ASSERT(allow_macro_instructions_);
561 VIXL_ASSERT(!rt.IsZero());
562 EmissionCheckScope guard(this, 2 * kInstructionSize);
563
564 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
565 Label done;
566 cbz(rt, &done);
567 b(label);
568 bind(&done);
569 } else {
570 if (!label->IsBound()) {
571 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
572 label,
573 CompareBranchType);
574 }
575 cbnz(rt, label);
576 }
577}
578
579
580void MacroAssembler::Cbz(const Register& rt, Label* label) {
581 VIXL_ASSERT(allow_macro_instructions_);
582 VIXL_ASSERT(!rt.IsZero());
583 EmissionCheckScope guard(this, 2 * kInstructionSize);
584
585 if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
586 Label done;
587 cbnz(rt, &done);
588 b(label);
589 bind(&done);
590 } else {
591 if (!label->IsBound()) {
592 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
593 label,
594 CompareBranchType);
595 }
596 cbz(rt, label);
597 }
598}
599
600
601void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
602 VIXL_ASSERT(allow_macro_instructions_);
603 VIXL_ASSERT(!rt.IsZero());
604 EmissionCheckScope guard(this, 2 * kInstructionSize);
605
606 if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
607 Label done;
608 tbz(rt, bit_pos, &done);
609 b(label);
610 bind(&done);
611 } else {
612 if (!label->IsBound()) {
613 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
614 label,
615 TestBranchType);
616 }
617 tbnz(rt, bit_pos, label);
618 }
619}
620
621
622void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
623 VIXL_ASSERT(allow_macro_instructions_);
624 VIXL_ASSERT(!rt.IsZero());
625 EmissionCheckScope guard(this, 2 * kInstructionSize);
626
627 if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
628 Label done;
629 tbnz(rt, bit_pos, &done);
630 b(label);
631 bind(&done);
632 } else {
633 if (!label->IsBound()) {
634 veneer_pool_.RegisterUnresolvedBranch(CursorOffset(),
635 label,
636 TestBranchType);
637 }
638 tbz(rt, bit_pos, label);
639 }
640}
641
642
643void MacroAssembler::Bind(Label* label) {
644 VIXL_ASSERT(allow_macro_instructions_);
645 veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
646 bind(label);
647}
648
649
650// Bind a label to a specified offset from the start of the buffer.
651void MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {
652 VIXL_ASSERT(allow_macro_instructions_);
653 veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
654 Assembler::BindToOffset(label, offset);
655}
656
657
armvixlad96eda2013-06-14 11:42:37 +0100658void MacroAssembler::And(const Register& rd,
659 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +0000660 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000661 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +0000662 LogicalMacro(rd, rn, operand, AND);
663}
664
665
666void MacroAssembler::Ands(const Register& rd,
667 const Register& rn,
668 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000669 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +0000670 LogicalMacro(rd, rn, operand, ANDS);
armvixlad96eda2013-06-14 11:42:37 +0100671}
672
673
armvixl0f35e362016-05-10 13:57:58 +0100674void MacroAssembler::Tst(const Register& rn, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000675 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +0000676 Ands(AppropriateZeroRegFor(rn), rn, operand);
armvixlad96eda2013-06-14 11:42:37 +0100677}
678
679
680void MacroAssembler::Bic(const Register& rd,
681 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +0000682 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000683 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +0000684 LogicalMacro(rd, rn, operand, BIC);
685}
686
687
688void MacroAssembler::Bics(const Register& rd,
689 const Register& rn,
690 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000691 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +0000692 LogicalMacro(rd, rn, operand, BICS);
armvixlad96eda2013-06-14 11:42:37 +0100693}
694
695
696void MacroAssembler::Orr(const Register& rd,
697 const Register& rn,
698 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000699 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +0100700 LogicalMacro(rd, rn, operand, ORR);
701}
702
703
704void MacroAssembler::Orn(const Register& rd,
705 const Register& rn,
706 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000707 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +0100708 LogicalMacro(rd, rn, operand, ORN);
709}
710
711
712void MacroAssembler::Eor(const Register& rd,
713 const Register& rn,
714 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000715 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +0100716 LogicalMacro(rd, rn, operand, EOR);
717}
718
719
720void MacroAssembler::Eon(const Register& rd,
721 const Register& rn,
722 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +0000723 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +0100724 LogicalMacro(rd, rn, operand, EON);
725}
726
727
728void MacroAssembler::LogicalMacro(const Register& rd,
729 const Register& rn,
730 const Operand& operand,
731 LogicalOp op) {
armvixlc68cb642014-09-25 18:49:30 +0100732 // The worst case for size is logical immediate to sp:
733 // * up to 4 instructions to materialise the constant
734 // * 1 instruction to do the operation
735 // * 1 instruction to move to sp
736 MacroEmissionCheckScope guard(this);
armvixlb0c8ae22014-03-21 14:03:59 +0000737 UseScratchRegisterScope temps(this);
738
armvixlad96eda2013-06-14 11:42:37 +0100739 if (operand.IsImmediate()) {
740 int64_t immediate = operand.immediate();
741 unsigned reg_size = rd.size();
armvixlad96eda2013-06-14 11:42:37 +0100742
743 // If the operation is NOT, invert the operation and immediate.
744 if ((op & NOT) == NOT) {
745 op = static_cast<LogicalOp>(op & ~NOT);
746 immediate = ~immediate;
armvixlad96eda2013-06-14 11:42:37 +0100747 }
748
armvixl4a102ba2014-07-14 09:02:40 +0100749 // Ignore the top 32 bits of an immediate if we're moving to a W register.
750 if (rd.Is32Bits()) {
751 // Check that the top 32 bits are consistent.
752 VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||
753 ((immediate >> kWRegSize) == -1));
754 immediate &= kWRegMask;
755 }
756
757 VIXL_ASSERT(rd.Is64Bits() || is_uint32(immediate));
758
armvixlad96eda2013-06-14 11:42:37 +0100759 // Special cases for all set or all clear immediates.
760 if (immediate == 0) {
761 switch (op) {
762 case AND:
763 Mov(rd, 0);
764 return;
armvixl6e2c8272015-03-31 11:04:14 +0100765 case ORR:
766 VIXL_FALLTHROUGH();
armvixlad96eda2013-06-14 11:42:37 +0100767 case EOR:
768 Mov(rd, rn);
769 return;
armvixl6e2c8272015-03-31 11:04:14 +0100770 case ANDS:
771 VIXL_FALLTHROUGH();
armvixlad96eda2013-06-14 11:42:37 +0100772 case BICS:
773 break;
774 default:
armvixlb0c8ae22014-03-21 14:03:59 +0000775 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +0100776 }
armvixlb0c8ae22014-03-21 14:03:59 +0000777 } else if ((rd.Is64Bits() && (immediate == -1)) ||
778 (rd.Is32Bits() && (immediate == 0xffffffff))) {
armvixlad96eda2013-06-14 11:42:37 +0100779 switch (op) {
780 case AND:
781 Mov(rd, rn);
782 return;
783 case ORR:
784 Mov(rd, immediate);
785 return;
786 case EOR:
787 Mvn(rd, rn);
788 return;
armvixl6e2c8272015-03-31 11:04:14 +0100789 case ANDS:
790 VIXL_FALLTHROUGH();
armvixlad96eda2013-06-14 11:42:37 +0100791 case BICS:
792 break;
793 default:
armvixlb0c8ae22014-03-21 14:03:59 +0000794 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +0100795 }
796 }
797
798 unsigned n, imm_s, imm_r;
799 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
800 // Immediate can be encoded in the instruction.
801 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
802 } else {
803 // Immediate can't be encoded: synthesize using move immediate.
armvixlb0c8ae22014-03-21 14:03:59 +0000804 Register temp = temps.AcquireSameSizeAs(rn);
armvixl4a102ba2014-07-14 09:02:40 +0100805 Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
806
armvixlad96eda2013-06-14 11:42:37 +0100807 if (rd.Is(sp)) {
808 // If rd is the stack pointer we cannot use it as the destination
809 // register so we use the temp register as an intermediate again.
armvixl4a102ba2014-07-14 09:02:40 +0100810 Logical(temp, rn, imm_operand, op);
armvixlad96eda2013-06-14 11:42:37 +0100811 Mov(sp, temp);
812 } else {
armvixl4a102ba2014-07-14 09:02:40 +0100813 Logical(rd, rn, imm_operand, op);
armvixlad96eda2013-06-14 11:42:37 +0100814 }
815 }
816 } else if (operand.IsExtendedRegister()) {
armvixlb0c8ae22014-03-21 14:03:59 +0000817 VIXL_ASSERT(operand.reg().size() <= rd.size());
armvixlad96eda2013-06-14 11:42:37 +0100818 // Add/sub extended supports shift <= 4. We want to support exactly the
819 // same modes here.
armvixlb0c8ae22014-03-21 14:03:59 +0000820 VIXL_ASSERT(operand.shift_amount() <= 4);
821 VIXL_ASSERT(operand.reg().Is64Bits() ||
armvixl0f35e362016-05-10 13:57:58 +0100822 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
armvixlb0c8ae22014-03-21 14:03:59 +0000823
824 temps.Exclude(operand.reg());
825 Register temp = temps.AcquireSameSizeAs(rn);
armvixl0f35e362016-05-10 13:57:58 +0100826 EmitExtendShift(temp,
827 operand.reg(),
828 operand.extend(),
armvixlad96eda2013-06-14 11:42:37 +0100829 operand.shift_amount());
830 Logical(rd, rn, Operand(temp), op);
831 } else {
832 // The operand can be encoded in the instruction.
armvixlb0c8ae22014-03-21 14:03:59 +0000833 VIXL_ASSERT(operand.IsShiftedRegister());
armvixlad96eda2013-06-14 11:42:37 +0100834 Logical(rd, rn, operand, op);
835 }
836}
837
838
armvixlf37fdc02014-02-05 13:22:16 +0000839void MacroAssembler::Mov(const Register& rd,
840 const Operand& operand,
841 DiscardMoveMode discard_mode) {
armvixlb0c8ae22014-03-21 14:03:59 +0000842 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +0100843 // The worst case for size is mov immediate with up to 4 instructions.
844 MacroEmissionCheckScope guard(this);
845
armvixlad96eda2013-06-14 11:42:37 +0100846 if (operand.IsImmediate()) {
847 // Call the macro assembler for generic immediates.
848 Mov(rd, operand.immediate());
849 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
850 // Emit a shift instruction if moving a shifted register. This operation
851 // could also be achieved using an orr instruction (like orn used by Mvn),
852 // but using a shift instruction makes the disassembly clearer.
853 EmitShift(rd, operand.reg(), operand.shift(), operand.shift_amount());
854 } else if (operand.IsExtendedRegister()) {
855 // Emit an extend instruction if moving an extended register. This handles
856 // extend with post-shift operations, too.
armvixl0f35e362016-05-10 13:57:58 +0100857 EmitExtendShift(rd,
858 operand.reg(),
859 operand.extend(),
armvixlad96eda2013-06-14 11:42:37 +0100860 operand.shift_amount());
861 } else {
862 // Otherwise, emit a register move only if the registers are distinct, or
armvixlf37fdc02014-02-05 13:22:16 +0000863 // if they are not X registers.
864 //
865 // Note that mov(w0, w0) is not a no-op because it clears the top word of
866 // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W
867 // registers is not required to clear the top word of the X register. In
868 // this case, the instruction is discarded.
869 //
armvixlad96eda2013-06-14 11:42:37 +0100870 // If the sp is an operand, add #0 is emitted, otherwise, orr #0.
armvixl0f35e362016-05-10 13:57:58 +0100871 if (!rd.Is(operand.reg()) ||
872 (rd.Is32Bits() && (discard_mode == kDontDiscardForSameWReg))) {
armvixlad96eda2013-06-14 11:42:37 +0100873 mov(rd, operand.reg());
874 }
875 }
876}
877
878
armvixl5289c592015-03-02 13:52:04 +0000879void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {
880 VIXL_ASSERT(is_uint16(imm));
881 int byte1 = (imm & 0xff);
882 int byte2 = ((imm >> 8) & 0xff);
883 if (byte1 == byte2) {
884 movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);
885 } else if (byte1 == 0) {
886 movi(vd, byte2, LSL, 8);
887 } else if (byte2 == 0) {
888 movi(vd, byte1);
889 } else if (byte1 == 0xff) {
890 mvni(vd, ~byte2 & 0xff, LSL, 8);
891 } else if (byte2 == 0xff) {
892 mvni(vd, ~byte1 & 0xff);
893 } else {
894 UseScratchRegisterScope temps(this);
895 Register temp = temps.AcquireW();
896 movz(temp, imm);
897 dup(vd, temp);
898 }
899}
900
901
902void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {
903 VIXL_ASSERT(is_uint32(imm));
904
905 uint8_t bytes[sizeof(imm)];
906 memcpy(bytes, &imm, sizeof(imm));
907
908 // All bytes are either 0x00 or 0xff.
909 {
910 bool all0orff = true;
911 for (int i = 0; i < 4; ++i) {
912 if ((bytes[i] != 0) && (bytes[i] != 0xff)) {
913 all0orff = false;
914 break;
915 }
916 }
917
918 if (all0orff == true) {
919 movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));
920 return;
921 }
922 }
923
924 // Of the 4 bytes, only one byte is non-zero.
925 for (int i = 0; i < 4; i++) {
926 if ((imm & (0xff << (i * 8))) == imm) {
927 movi(vd, bytes[i], LSL, i * 8);
928 return;
929 }
930 }
931
932 // Of the 4 bytes, only one byte is not 0xff.
933 for (int i = 0; i < 4; i++) {
934 uint32_t mask = ~(0xff << (i * 8));
935 if ((imm & mask) == mask) {
936 mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);
937 return;
938 }
939 }
940
941 // Immediate is of the form 0x00MMFFFF.
942 if ((imm & 0xff00ffff) == 0x0000ffff) {
943 movi(vd, bytes[2], MSL, 16);
944 return;
945 }
946
947 // Immediate is of the form 0x0000MMFF.
948 if ((imm & 0xffff00ff) == 0x000000ff) {
949 movi(vd, bytes[1], MSL, 8);
950 return;
951 }
952
953 // Immediate is of the form 0xFFMM0000.
954 if ((imm & 0xff00ffff) == 0xff000000) {
955 mvni(vd, ~bytes[2] & 0xff, MSL, 16);
956 return;
957 }
958 // Immediate is of the form 0xFFFFMM00.
959 if ((imm & 0xffff00ff) == 0xffff0000) {
960 mvni(vd, ~bytes[1] & 0xff, MSL, 8);
961 return;
962 }
963
964 // Top and bottom 16-bits are equal.
965 if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {
966 Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);
967 return;
968 }
969
970 // Default case.
971 {
972 UseScratchRegisterScope temps(this);
973 Register temp = temps.AcquireW();
974 Mov(temp, imm);
975 dup(vd, temp);
976 }
977}
978
979
980void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
981 // All bytes are either 0x00 or 0xff.
982 {
983 bool all0orff = true;
984 for (int i = 0; i < 8; ++i) {
985 int byteval = (imm >> (i * 8)) & 0xff;
986 if (byteval != 0 && byteval != 0xff) {
987 all0orff = false;
988 break;
989 }
990 }
991 if (all0orff == true) {
992 movi(vd, imm);
993 return;
994 }
995 }
996
997 // Top and bottom 32-bits are equal.
998 if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {
999 Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);
1000 return;
1001 }
1002
1003 // Default case.
1004 {
1005 UseScratchRegisterScope temps(this);
1006 Register temp = temps.AcquireX();
1007 Mov(temp, imm);
1008 if (vd.Is1D()) {
1009 mov(vd.D(), 0, temp);
1010 } else {
1011 dup(vd.V2D(), temp);
1012 }
1013 }
1014}
1015
1016
1017void MacroAssembler::Movi(const VRegister& vd,
1018 uint64_t imm,
1019 Shift shift,
1020 int shift_amount) {
1021 VIXL_ASSERT(allow_macro_instructions_);
1022 MacroEmissionCheckScope guard(this);
1023 if (shift_amount != 0 || shift != LSL) {
1024 movi(vd, imm, shift, shift_amount);
1025 } else if (vd.Is8B() || vd.Is16B()) {
1026 // 8-bit immediate.
1027 VIXL_ASSERT(is_uint8(imm));
1028 movi(vd, imm);
1029 } else if (vd.Is4H() || vd.Is8H()) {
1030 // 16-bit immediate.
1031 Movi16bitHelper(vd, imm);
1032 } else if (vd.Is2S() || vd.Is4S()) {
1033 // 32-bit immediate.
1034 Movi32bitHelper(vd, imm);
1035 } else {
1036 // 64-bit immediate.
1037 Movi64bitHelper(vd, imm);
1038 }
1039}
1040
1041
armvixl0f35e362016-05-10 13:57:58 +01001042void MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) {
armvixl5289c592015-03-02 13:52:04 +00001043 // TODO: Move 128-bit values in a more efficient way.
1044 VIXL_ASSERT(vd.Is128Bits());
1045 UseScratchRegisterScope temps(this);
1046 Movi(vd.V2D(), lo);
1047 Register temp = temps.AcquireX();
1048 Mov(temp, hi);
1049 Ins(vd.V2D(), 1, temp);
1050}
1051
1052
armvixlad96eda2013-06-14 11:42:37 +01001053void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001054 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001055 // The worst case for size is mvn immediate with up to 4 instructions.
1056 MacroEmissionCheckScope guard(this);
1057
armvixlad96eda2013-06-14 11:42:37 +01001058 if (operand.IsImmediate()) {
1059 // Call the macro assembler for generic immediates.
1060 Mvn(rd, operand.immediate());
1061 } else if (operand.IsExtendedRegister()) {
armvixlb0c8ae22014-03-21 14:03:59 +00001062 UseScratchRegisterScope temps(this);
1063 temps.Exclude(operand.reg());
1064
armvixlad96eda2013-06-14 11:42:37 +01001065 // Emit two instructions for the extend case. This differs from Mov, as
1066 // the extend and invert can't be achieved in one instruction.
armvixlb0c8ae22014-03-21 14:03:59 +00001067 Register temp = temps.AcquireSameSizeAs(rd);
armvixl0f35e362016-05-10 13:57:58 +01001068 EmitExtendShift(temp,
1069 operand.reg(),
1070 operand.extend(),
armvixlad96eda2013-06-14 11:42:37 +01001071 operand.shift_amount());
1072 mvn(rd, Operand(temp));
1073 } else {
1074 // Otherwise, register and shifted register cases can be handled by the
1075 // assembler directly, using orn.
1076 mvn(rd, operand);
1077 }
1078}
1079
1080
1081void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
armvixlb0c8ae22014-03-21 14:03:59 +00001082 VIXL_ASSERT(allow_macro_instructions_);
armvixl330dc712014-11-25 10:38:32 +00001083 MoveImmediateHelper(this, rd, imm);
armvixlad96eda2013-06-14 11:42:37 +01001084}
1085
1086
1087void MacroAssembler::Ccmp(const Register& rn,
1088 const Operand& operand,
1089 StatusFlags nzcv,
1090 Condition cond) {
armvixlb0c8ae22014-03-21 14:03:59 +00001091 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001092 if (operand.IsImmediate() && (operand.immediate() < 0)) {
1093 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN);
1094 } else {
1095 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
1096 }
armvixlad96eda2013-06-14 11:42:37 +01001097}
1098
1099
1100void MacroAssembler::Ccmn(const Register& rn,
1101 const Operand& operand,
1102 StatusFlags nzcv,
1103 Condition cond) {
armvixlb0c8ae22014-03-21 14:03:59 +00001104 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001105 if (operand.IsImmediate() && (operand.immediate() < 0)) {
1106 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP);
1107 } else {
1108 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
1109 }
armvixlad96eda2013-06-14 11:42:37 +01001110}
1111
1112
1113void MacroAssembler::ConditionalCompareMacro(const Register& rn,
1114 const Operand& operand,
1115 StatusFlags nzcv,
1116 Condition cond,
1117 ConditionalCompareOp op) {
armvixlb0c8ae22014-03-21 14:03:59 +00001118 VIXL_ASSERT((cond != al) && (cond != nv));
armvixlc68cb642014-09-25 18:49:30 +01001119 // The worst case for size is ccmp immediate:
1120 // * up to 4 instructions to materialise the constant
1121 // * 1 instruction for ccmp
1122 MacroEmissionCheckScope guard(this);
1123
armvixlad96eda2013-06-14 11:42:37 +01001124 if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) ||
1125 (operand.IsImmediate() && IsImmConditionalCompare(operand.immediate()))) {
1126 // The immediate can be encoded in the instruction, or the operand is an
1127 // unshifted register: call the assembler.
1128 ConditionalCompare(rn, operand, nzcv, cond, op);
1129 } else {
armvixlb0c8ae22014-03-21 14:03:59 +00001130 UseScratchRegisterScope temps(this);
armvixlad96eda2013-06-14 11:42:37 +01001131 // The operand isn't directly supported by the instruction: perform the
1132 // operation on a temporary register.
armvixlb0c8ae22014-03-21 14:03:59 +00001133 Register temp = temps.AcquireSameSizeAs(rn);
armvixlf37fdc02014-02-05 13:22:16 +00001134 Mov(temp, operand);
1135 ConditionalCompare(rn, temp, nzcv, cond, op);
1136 }
1137}
1138
1139
armvixl0f35e362016-05-10 13:57:58 +01001140void MacroAssembler::CselHelper(MacroAssembler* masm,
1141 const Register& rd,
1142 Operand left,
1143 Operand right,
1144 Condition cond,
1145 bool* should_synthesise_left,
1146 bool* should_synthesise_right) {
1147 bool emit_code = (masm != NULL);
armvixlc68cb642014-09-25 18:49:30 +01001148
armvixl0f35e362016-05-10 13:57:58 +01001149 VIXL_ASSERT(!emit_code || masm->allow_macro_instructions_);
1150 VIXL_ASSERT((cond != al) && (cond != nv));
1151 VIXL_ASSERT(!rd.IsZero() && !rd.IsSP());
1152 VIXL_ASSERT(left.IsImmediate() || !left.reg().IsSP());
1153 VIXL_ASSERT(right.IsImmediate() || !right.reg().IsSP());
1154
1155 if (should_synthesise_left != NULL) *should_synthesise_left = false;
1156 if (should_synthesise_right != NULL) *should_synthesise_right = false;
1157
1158 // The worst case for size occurs when the inputs are two non encodable
1159 // constants:
1160 // * up to 4 instructions to materialise the left constant
1161 // * up to 4 instructions to materialise the right constant
1162 // * 1 instruction for csel
1163 EmissionCheckScope guard(masm, 9 * kInstructionSize);
1164 UseScratchRegisterScope temps;
1165 if (masm != NULL) {
1166 temps.Open(masm);
1167 }
1168
1169 // Try to handle cases where both inputs are immediates.
1170 bool left_is_immediate = left.IsImmediate() || left.IsZero();
1171 bool right_is_immediate = right.IsImmediate() || right.IsZero();
1172 if (left_is_immediate && right_is_immediate &&
1173 CselSubHelperTwoImmediates(masm,
1174 rd,
1175 left.GetEquivalentImmediate(),
1176 right.GetEquivalentImmediate(),
1177 cond,
1178 should_synthesise_left,
1179 should_synthesise_right)) {
1180 return;
1181 }
1182
1183 // Handle cases where one of the two inputs is -1, 0, or 1.
1184 bool left_is_small_immediate =
1185 left_is_immediate && ((-1 <= left.GetEquivalentImmediate()) &&
1186 (left.GetEquivalentImmediate() <= 1));
1187 bool right_is_small_immediate =
1188 right_is_immediate && ((-1 <= right.GetEquivalentImmediate()) &&
1189 (right.GetEquivalentImmediate() <= 1));
1190 if (right_is_small_immediate || left_is_small_immediate) {
1191 bool swapped_inputs = false;
1192 if (!right_is_small_immediate) {
1193 std::swap(left, right);
1194 cond = InvertCondition(cond);
1195 swapped_inputs = true;
armvixlad96eda2013-06-14 11:42:37 +01001196 }
armvixl0f35e362016-05-10 13:57:58 +01001197 CselSubHelperRightSmallImmediate(masm,
1198 &temps,
1199 rd,
1200 left,
1201 right,
1202 cond,
1203 swapped_inputs ? should_synthesise_right
1204 : should_synthesise_left);
1205 return;
1206 }
1207
1208 // Otherwise both inputs need to be available in registers. Synthesise them
1209 // if necessary and emit the `csel`.
1210 if (!left.IsPlainRegister()) {
1211 if (emit_code) {
1212 Register temp = temps.AcquireSameSizeAs(rd);
1213 masm->Mov(temp, left);
1214 left = temp;
1215 }
1216 if (should_synthesise_left != NULL) *should_synthesise_left = true;
1217 }
1218 if (!right.IsPlainRegister()) {
1219 if (emit_code) {
1220 Register temp = temps.AcquireSameSizeAs(rd);
1221 masm->Mov(temp, right);
1222 right = temp;
1223 }
1224 if (should_synthesise_right != NULL) *should_synthesise_right = true;
1225 }
1226 if (emit_code) {
1227 VIXL_ASSERT(left.IsPlainRegister() && right.IsPlainRegister());
1228 if (left.reg().Is(right.reg())) {
1229 masm->Mov(rd, left.reg());
1230 } else {
1231 masm->csel(rd, left.reg(), right.reg(), cond);
1232 }
1233 }
1234}
1235
1236
1237bool MacroAssembler::CselSubHelperTwoImmediates(MacroAssembler* masm,
1238 const Register& rd,
1239 int64_t left,
1240 int64_t right,
1241 Condition cond,
1242 bool* should_synthesise_left,
1243 bool* should_synthesise_right) {
1244 bool emit_code = (masm != NULL);
1245 if (should_synthesise_left != NULL) *should_synthesise_left = false;
1246 if (should_synthesise_right != NULL) *should_synthesise_right = false;
1247
1248 if (left == right) {
1249 if (emit_code) masm->Mov(rd, left);
1250 return true;
1251 } else if (left == -right) {
1252 if (should_synthesise_right != NULL) *should_synthesise_right = true;
1253 if (emit_code) {
1254 masm->Mov(rd, right);
1255 masm->Cneg(rd, rd, cond);
1256 }
1257 return true;
1258 }
1259
1260 if (CselSubHelperTwoOrderedImmediates(masm, rd, left, right, cond)) {
1261 return true;
armvixlf37fdc02014-02-05 13:22:16 +00001262 } else {
armvixl0f35e362016-05-10 13:57:58 +01001263 std::swap(left, right);
1264 if (CselSubHelperTwoOrderedImmediates(masm,
1265 rd,
1266 left,
1267 right,
1268 InvertCondition(cond))) {
1269 return true;
1270 }
1271 }
1272
1273 // TODO: Handle more situations. For example handle `csel rd, #5, #6, cond`
1274 // with `cinc`.
1275 return false;
1276}
1277
1278
1279bool MacroAssembler::CselSubHelperTwoOrderedImmediates(MacroAssembler* masm,
1280 const Register& rd,
1281 int64_t left,
1282 int64_t right,
1283 Condition cond) {
1284 bool emit_code = (masm != NULL);
1285
Alexandre Rames2fbea6c2016-06-07 09:21:11 +01001286 if ((left == 1) && (right == 0)) {
armvixl0f35e362016-05-10 13:57:58 +01001287 if (emit_code) masm->cset(rd, cond);
1288 return true;
Alexandre Rames2fbea6c2016-06-07 09:21:11 +01001289 } else if ((left == -1) && (right == 0)) {
1290 if (emit_code) masm->csetm(rd, cond);
armvixl0f35e362016-05-10 13:57:58 +01001291 return true;
1292 }
1293 return false;
1294}
1295
1296
1297void MacroAssembler::CselSubHelperRightSmallImmediate(
1298 MacroAssembler* masm,
1299 UseScratchRegisterScope* temps,
1300 const Register& rd,
1301 const Operand& left,
1302 const Operand& right,
1303 Condition cond,
1304 bool* should_synthesise_left) {
1305 bool emit_code = (masm != NULL);
1306 VIXL_ASSERT((right.IsImmediate() || right.IsZero()) &&
1307 (-1 <= right.GetEquivalentImmediate()) &&
1308 (right.GetEquivalentImmediate() <= 1));
1309 Register left_register;
1310
1311 if (left.IsPlainRegister()) {
1312 left_register = left.reg();
1313 } else {
1314 if (emit_code) {
1315 left_register = temps->AcquireSameSizeAs(rd);
1316 masm->Mov(left_register, left);
1317 }
1318 if (should_synthesise_left != NULL) *should_synthesise_left = true;
1319 }
1320 if (emit_code) {
1321 int64_t imm = right.GetEquivalentImmediate();
1322 Register zr = AppropriateZeroRegFor(rd);
1323 if (imm == 0) {
1324 masm->csel(rd, left_register, zr, cond);
1325 } else if (imm == 1) {
1326 masm->csinc(rd, left_register, zr, cond);
1327 } else {
1328 VIXL_ASSERT(imm == -1);
1329 masm->csinv(rd, left_register, zr, cond);
1330 }
armvixlad96eda2013-06-14 11:42:37 +01001331 }
1332}
1333
1334
1335void MacroAssembler::Add(const Register& rd,
1336 const Register& rn,
armvixl6e2c8272015-03-31 11:04:14 +01001337 const Operand& operand,
1338 FlagsUpdate S) {
armvixlb0c8ae22014-03-21 14:03:59 +00001339 VIXL_ASSERT(allow_macro_instructions_);
armvixl4a102ba2014-07-14 09:02:40 +01001340 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1341 IsImmAddSub(-operand.immediate())) {
armvixl6e2c8272015-03-31 11:04:14 +01001342 AddSubMacro(rd, rn, -operand.immediate(), S, SUB);
armvixlad96eda2013-06-14 11:42:37 +01001343 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001344 AddSubMacro(rd, rn, operand, S, ADD);
armvixlf37fdc02014-02-05 13:22:16 +00001345 }
1346}
1347
1348
1349void MacroAssembler::Adds(const Register& rd,
1350 const Register& rn,
1351 const Operand& operand) {
armvixl6e2c8272015-03-31 11:04:14 +01001352 Add(rd, rn, operand, SetFlags);
armvixlad96eda2013-06-14 11:42:37 +01001353}
1354
1355
1356void MacroAssembler::Sub(const Register& rd,
1357 const Register& rn,
armvixl6e2c8272015-03-31 11:04:14 +01001358 const Operand& operand,
1359 FlagsUpdate S) {
armvixlb0c8ae22014-03-21 14:03:59 +00001360 VIXL_ASSERT(allow_macro_instructions_);
armvixl4a102ba2014-07-14 09:02:40 +01001361 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1362 IsImmAddSub(-operand.immediate())) {
armvixl6e2c8272015-03-31 11:04:14 +01001363 AddSubMacro(rd, rn, -operand.immediate(), S, ADD);
armvixlad96eda2013-06-14 11:42:37 +01001364 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001365 AddSubMacro(rd, rn, operand, S, SUB);
armvixlf37fdc02014-02-05 13:22:16 +00001366 }
1367}
1368
1369
1370void MacroAssembler::Subs(const Register& rd,
1371 const Register& rn,
1372 const Operand& operand) {
armvixl6e2c8272015-03-31 11:04:14 +01001373 Sub(rd, rn, operand, SetFlags);
armvixlad96eda2013-06-14 11:42:37 +01001374}
1375
1376
1377void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001378 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001379 Adds(AppropriateZeroRegFor(rn), rn, operand);
armvixlad96eda2013-06-14 11:42:37 +01001380}
1381
1382
1383void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001384 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001385 Subs(AppropriateZeroRegFor(rn), rn, operand);
armvixlad96eda2013-06-14 11:42:37 +01001386}
1387
1388
armvixl0f35e362016-05-10 13:57:58 +01001389void MacroAssembler::Fcmp(const FPRegister& fn,
1390 double value,
armvixl6e2c8272015-03-31 11:04:14 +01001391 FPTrapFlags trap) {
armvixlb0c8ae22014-03-21 14:03:59 +00001392 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001393 // The worst case for size is:
1394 // * 1 to materialise the constant, using literal pool if necessary
armvixl6e2c8272015-03-31 11:04:14 +01001395 // * 1 instruction for fcmp{e}
armvixlc68cb642014-09-25 18:49:30 +01001396 MacroEmissionCheckScope guard(this);
armvixlb0c8ae22014-03-21 14:03:59 +00001397 if (value != 0.0) {
1398 UseScratchRegisterScope temps(this);
1399 FPRegister tmp = temps.AcquireSameSizeAs(fn);
1400 Fmov(tmp, value);
armvixl6e2c8272015-03-31 11:04:14 +01001401 FPCompareMacro(fn, tmp, trap);
armvixlb0c8ae22014-03-21 14:03:59 +00001402 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001403 FPCompareMacro(fn, value, trap);
armvixlb0c8ae22014-03-21 14:03:59 +00001404 }
1405}
1406
1407
armvixl6e2c8272015-03-31 11:04:14 +01001408void MacroAssembler::Fcmpe(const FPRegister& fn, double value) {
1409 Fcmp(fn, value, EnableTrap);
1410}
1411
1412
armvixl5289c592015-03-02 13:52:04 +00001413void MacroAssembler::Fmov(VRegister vd, double imm) {
armvixlb0c8ae22014-03-21 14:03:59 +00001414 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001415 // Floating point immediates are loaded through the literal pool.
1416 MacroEmissionCheckScope guard(this);
1417
armvixl5289c592015-03-02 13:52:04 +00001418 if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1419 Fmov(vd, static_cast<float>(imm));
armvixlb0c8ae22014-03-21 14:03:59 +00001420 return;
1421 }
1422
armvixl5289c592015-03-02 13:52:04 +00001423 VIXL_ASSERT(vd.Is1D() || vd.Is2D());
armvixlb0c8ae22014-03-21 14:03:59 +00001424 if (IsImmFP64(imm)) {
armvixl5289c592015-03-02 13:52:04 +00001425 fmov(vd, imm);
armvixlb0c8ae22014-03-21 14:03:59 +00001426 } else {
armvixl5289c592015-03-02 13:52:04 +00001427 uint64_t rawbits = double_to_rawbits(imm);
1428 if (vd.IsScalar()) {
1429 if (rawbits == 0) {
1430 fmov(vd, xzr);
1431 } else {
armvixldb644342015-07-21 11:37:10 +01001432 ldr(vd,
1433 new Literal<double>(imm,
1434 &literal_pool_,
1435 RawLiteral::kDeletedOnPlacementByPool));
armvixl5289c592015-03-02 13:52:04 +00001436 }
1437 } else {
1438 // TODO: consider NEON support for load literal.
1439 Movi(vd, rawbits);
1440 }
armvixlb0c8ae22014-03-21 14:03:59 +00001441 }
1442}
1443
1444
armvixl5289c592015-03-02 13:52:04 +00001445void MacroAssembler::Fmov(VRegister vd, float imm) {
armvixlb0c8ae22014-03-21 14:03:59 +00001446 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001447 // Floating point immediates are loaded through the literal pool.
1448 MacroEmissionCheckScope guard(this);
1449
armvixl5289c592015-03-02 13:52:04 +00001450 if (vd.Is1D() || vd.Is2D()) {
1451 Fmov(vd, static_cast<double>(imm));
armvixlb0c8ae22014-03-21 14:03:59 +00001452 return;
1453 }
1454
armvixl5289c592015-03-02 13:52:04 +00001455 VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
armvixlb0c8ae22014-03-21 14:03:59 +00001456 if (IsImmFP32(imm)) {
armvixl5289c592015-03-02 13:52:04 +00001457 fmov(vd, imm);
armvixlb0c8ae22014-03-21 14:03:59 +00001458 } else {
armvixl5289c592015-03-02 13:52:04 +00001459 uint32_t rawbits = float_to_rawbits(imm);
1460 if (vd.IsScalar()) {
1461 if (rawbits == 0) {
1462 fmov(vd, wzr);
1463 } else {
armvixldb644342015-07-21 11:37:10 +01001464 ldr(vd,
1465 new Literal<float>(imm,
1466 &literal_pool_,
1467 RawLiteral::kDeletedOnPlacementByPool));
armvixl5289c592015-03-02 13:52:04 +00001468 }
1469 } else {
1470 // TODO: consider NEON support for load literal.
1471 Movi(vd, rawbits);
1472 }
armvixlb0c8ae22014-03-21 14:03:59 +00001473 }
1474}
1475
1476
armvixl0f35e362016-05-10 13:57:58 +01001477void MacroAssembler::Neg(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001478 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001479 if (operand.IsImmediate()) {
1480 Mov(rd, -operand.immediate());
1481 } else {
armvixlf37fdc02014-02-05 13:22:16 +00001482 Sub(rd, AppropriateZeroRegFor(rd), operand);
armvixlad96eda2013-06-14 11:42:37 +01001483 }
1484}
1485
1486
armvixl0f35e362016-05-10 13:57:58 +01001487void MacroAssembler::Negs(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001488 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001489 Subs(rd, AppropriateZeroRegFor(rd), operand);
1490}
1491
1492
armvixl4a102ba2014-07-14 09:02:40 +01001493bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
1494 int64_t imm) {
armvixl330dc712014-11-25 10:38:32 +00001495 return OneInstrMoveImmediateHelper(this, dst, imm);
armvixl4a102ba2014-07-14 09:02:40 +01001496}
1497
1498
1499Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
1500 int64_t imm) {
1501 int reg_size = dst.size();
1502
1503 // Encode the immediate in a single move instruction, if possible.
1504 if (TryOneInstrMoveImmediate(dst, imm)) {
1505 // The move was successful; nothing to do here.
1506 } else {
1507 // Pre-shift the immediate to the least-significant bits of the register.
1508 int shift_low = CountTrailingZeros(imm, reg_size);
1509 int64_t imm_low = imm >> shift_low;
1510
1511 // Pre-shift the immediate to the most-significant bits of the register,
1512 // inserting set bits in the least-significant bits.
1513 int shift_high = CountLeadingZeros(imm, reg_size);
armvixl5289c592015-03-02 13:52:04 +00001514 int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
armvixl4a102ba2014-07-14 09:02:40 +01001515
1516 if (TryOneInstrMoveImmediate(dst, imm_low)) {
1517 // The new immediate has been moved into the destination's low bits:
1518 // return a new leftward-shifting operand.
1519 return Operand(dst, LSL, shift_low);
1520 } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
1521 // The new immediate has been moved into the destination's high bits:
1522 // return a new rightward-shifting operand.
1523 return Operand(dst, LSR, shift_high);
1524 } else {
1525 Mov(dst, imm);
1526 }
1527 }
1528 return Operand(dst);
1529}
1530
1531
armvixl5289c592015-03-02 13:52:04 +00001532void MacroAssembler::ComputeAddress(const Register& dst,
1533 const MemOperand& mem_op) {
1534 // We cannot handle pre-indexing or post-indexing.
1535 VIXL_ASSERT(mem_op.addrmode() == Offset);
1536 Register base = mem_op.base();
1537 if (mem_op.IsImmediateOffset()) {
1538 Add(dst, base, mem_op.offset());
1539 } else {
1540 VIXL_ASSERT(mem_op.IsRegisterOffset());
1541 Register reg_offset = mem_op.regoffset();
1542 Shift shift = mem_op.shift();
1543 Extend extend = mem_op.extend();
1544 if (shift == NO_SHIFT) {
1545 VIXL_ASSERT(extend != NO_EXTEND);
1546 Add(dst, base, Operand(reg_offset, extend, mem_op.shift_amount()));
1547 } else {
1548 VIXL_ASSERT(extend == NO_EXTEND);
1549 Add(dst, base, Operand(reg_offset, shift, mem_op.shift_amount()));
1550 }
1551 }
1552}
1553
1554
armvixlad96eda2013-06-14 11:42:37 +01001555void MacroAssembler::AddSubMacro(const Register& rd,
1556 const Register& rn,
1557 const Operand& operand,
1558 FlagsUpdate S,
1559 AddSubOp op) {
armvixlc68cb642014-09-25 18:49:30 +01001560 // Worst case is add/sub immediate:
1561 // * up to 4 instructions to materialise the constant
1562 // * 1 instruction for add/sub
1563 MacroEmissionCheckScope guard(this);
1564
armvixlf37fdc02014-02-05 13:22:16 +00001565 if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1566 (S == LeaveFlags)) {
1567 // The instruction would be a nop. Avoid generating useless code.
1568 return;
1569 }
1570
armvixlad96eda2013-06-14 11:42:37 +01001571 if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
armvixl0f35e362016-05-10 13:57:58 +01001572 (rn.IsZero() && !operand.IsShiftedRegister()) ||
armvixlad96eda2013-06-14 11:42:37 +01001573 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
armvixlb0c8ae22014-03-21 14:03:59 +00001574 UseScratchRegisterScope temps(this);
1575 Register temp = temps.AcquireSameSizeAs(rn);
armvixl4a102ba2014-07-14 09:02:40 +01001576 if (operand.IsImmediate()) {
1577 Operand imm_operand =
1578 MoveImmediateForShiftedOp(temp, operand.immediate());
1579 AddSub(rd, rn, imm_operand, S, op);
1580 } else {
1581 Mov(temp, operand);
1582 AddSub(rd, rn, temp, S, op);
1583 }
armvixlad96eda2013-06-14 11:42:37 +01001584 } else {
1585 AddSub(rd, rn, operand, S, op);
1586 }
1587}
1588
1589
1590void MacroAssembler::Adc(const Register& rd,
1591 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +00001592 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001593 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001594 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1595}
1596
1597
1598void MacroAssembler::Adcs(const Register& rd,
1599 const Register& rn,
1600 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001601 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001602 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
armvixlad96eda2013-06-14 11:42:37 +01001603}
1604
1605
1606void MacroAssembler::Sbc(const Register& rd,
1607 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +00001608 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001609 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001610 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1611}
1612
1613
1614void MacroAssembler::Sbcs(const Register& rd,
1615 const Register& rn,
1616 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001617 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001618 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
armvixlad96eda2013-06-14 11:42:37 +01001619}
1620
1621
armvixl0f35e362016-05-10 13:57:58 +01001622void MacroAssembler::Ngc(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001623 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001624 Register zr = AppropriateZeroRegFor(rd);
armvixlf37fdc02014-02-05 13:22:16 +00001625 Sbc(rd, zr, operand);
1626}
1627
1628
armvixl0f35e362016-05-10 13:57:58 +01001629void MacroAssembler::Ngcs(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001630 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001631 Register zr = AppropriateZeroRegFor(rd);
1632 Sbcs(rd, zr, operand);
armvixlad96eda2013-06-14 11:42:37 +01001633}
1634
1635
1636void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1637 const Register& rn,
1638 const Operand& operand,
1639 FlagsUpdate S,
1640 AddSubWithCarryOp op) {
armvixlb0c8ae22014-03-21 14:03:59 +00001641 VIXL_ASSERT(rd.size() == rn.size());
armvixlc68cb642014-09-25 18:49:30 +01001642 // Worst case is addc/subc immediate:
1643 // * up to 4 instructions to materialise the constant
1644 // * 1 instruction for add/sub
1645 MacroEmissionCheckScope guard(this);
armvixlb0c8ae22014-03-21 14:03:59 +00001646 UseScratchRegisterScope temps(this);
armvixlad96eda2013-06-14 11:42:37 +01001647
1648 if (operand.IsImmediate() ||
1649 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1650 // Add/sub with carry (immediate or ROR shifted register.)
armvixlb0c8ae22014-03-21 14:03:59 +00001651 Register temp = temps.AcquireSameSizeAs(rn);
armvixlad96eda2013-06-14 11:42:37 +01001652 Mov(temp, operand);
1653 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1654 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
1655 // Add/sub with carry (shifted register).
armvixlb0c8ae22014-03-21 14:03:59 +00001656 VIXL_ASSERT(operand.reg().size() == rd.size());
1657 VIXL_ASSERT(operand.shift() != ROR);
1658 VIXL_ASSERT(is_uintn(rd.size() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
armvixl0f35e362016-05-10 13:57:58 +01001659 operand.shift_amount()));
armvixlb0c8ae22014-03-21 14:03:59 +00001660 temps.Exclude(operand.reg());
1661 Register temp = temps.AcquireSameSizeAs(rn);
armvixlad96eda2013-06-14 11:42:37 +01001662 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
1663 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1664 } else if (operand.IsExtendedRegister()) {
1665 // Add/sub with carry (extended register).
armvixlb0c8ae22014-03-21 14:03:59 +00001666 VIXL_ASSERT(operand.reg().size() <= rd.size());
armvixlad96eda2013-06-14 11:42:37 +01001667 // Add/sub extended supports a shift <= 4. We want to support exactly the
1668 // same modes.
armvixlb0c8ae22014-03-21 14:03:59 +00001669 VIXL_ASSERT(operand.shift_amount() <= 4);
1670 VIXL_ASSERT(operand.reg().Is64Bits() ||
armvixl0f35e362016-05-10 13:57:58 +01001671 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
armvixlb0c8ae22014-03-21 14:03:59 +00001672 temps.Exclude(operand.reg());
1673 Register temp = temps.AcquireSameSizeAs(rn);
armvixl0f35e362016-05-10 13:57:58 +01001674 EmitExtendShift(temp,
1675 operand.reg(),
1676 operand.extend(),
armvixlad96eda2013-06-14 11:42:37 +01001677 operand.shift_amount());
1678 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1679 } else {
1680 // The addressing mode is directly supported by the instruction.
1681 AddSubWithCarry(rd, rn, operand, S, op);
1682 }
1683}
1684
1685
armvixl0f35e362016-05-10 13:57:58 +01001686#define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
1687 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
1688 VIXL_ASSERT(allow_macro_instructions_); \
1689 LoadStoreMacro(REG, addr, OP); \
1690 }
armvixlad96eda2013-06-14 11:42:37 +01001691LS_MACRO_LIST(DEFINE_FUNCTION)
1692#undef DEFINE_FUNCTION
1693
armvixl330dc712014-11-25 10:38:32 +00001694
armvixlad96eda2013-06-14 11:42:37 +01001695void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
1696 const MemOperand& addr,
1697 LoadStoreOp op) {
armvixlc68cb642014-09-25 18:49:30 +01001698 // Worst case is ldr/str pre/post index:
1699 // * 1 instruction for ldr/str
1700 // * up to 4 instructions to materialise the constant
1701 // * 1 instruction to update the base
1702 MacroEmissionCheckScope guard(this);
1703
armvixlad96eda2013-06-14 11:42:37 +01001704 int64_t offset = addr.offset();
armvixl5289c592015-03-02 13:52:04 +00001705 unsigned access_size = CalcLSDataSize(op);
armvixlad96eda2013-06-14 11:42:37 +01001706
1707 // Check if an immediate offset fits in the immediate field of the
1708 // appropriate instruction. If not, emit two instructions to perform
1709 // the operation.
armvixl5289c592015-03-02 13:52:04 +00001710 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
armvixlad96eda2013-06-14 11:42:37 +01001711 !IsImmLSUnscaled(offset)) {
1712 // Immediate offset that can't be encoded using unsigned or unscaled
1713 // addressing modes.
armvixlb0c8ae22014-03-21 14:03:59 +00001714 UseScratchRegisterScope temps(this);
1715 Register temp = temps.AcquireSameSizeAs(addr.base());
armvixlad96eda2013-06-14 11:42:37 +01001716 Mov(temp, addr.offset());
1717 LoadStore(rt, MemOperand(addr.base(), temp), op);
1718 } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
1719 // Post-index beyond unscaled addressing range.
1720 LoadStore(rt, MemOperand(addr.base()), op);
1721 Add(addr.base(), addr.base(), Operand(offset));
1722 } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
1723 // Pre-index beyond unscaled addressing range.
1724 Add(addr.base(), addr.base(), Operand(offset));
1725 LoadStore(rt, MemOperand(addr.base()), op);
1726 } else {
1727 // Encodable in one load/store instruction.
1728 LoadStore(rt, addr, op);
1729 }
1730}
1731
1732
armvixl0f35e362016-05-10 13:57:58 +01001733#define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
1734 void MacroAssembler::FN(const REGTYPE REG, \
1735 const REGTYPE REG2, \
1736 const MemOperand& addr) { \
1737 VIXL_ASSERT(allow_macro_instructions_); \
1738 LoadStorePairMacro(REG, REG2, addr, OP); \
1739 }
armvixlc68cb642014-09-25 18:49:30 +01001740LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
1741#undef DEFINE_FUNCTION
1742
1743void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
1744 const CPURegister& rt2,
1745 const MemOperand& addr,
1746 LoadStorePairOp op) {
1747 // TODO(all): Should we support register offset for load-store-pair?
1748 VIXL_ASSERT(!addr.IsRegisterOffset());
1749 // Worst case is ldp/stp immediate:
1750 // * 1 instruction for ldp/stp
1751 // * up to 4 instructions to materialise the constant
1752 // * 1 instruction to update the base
1753 MacroEmissionCheckScope guard(this);
1754
1755 int64_t offset = addr.offset();
armvixl5289c592015-03-02 13:52:04 +00001756 unsigned access_size = CalcLSPairDataSize(op);
armvixlc68cb642014-09-25 18:49:30 +01001757
1758 // Check if the offset fits in the immediate field of the appropriate
1759 // instruction. If not, emit two instructions to perform the operation.
armvixl5289c592015-03-02 13:52:04 +00001760 if (IsImmLSPair(offset, access_size)) {
armvixlc68cb642014-09-25 18:49:30 +01001761 // Encodable in one load/store pair instruction.
1762 LoadStorePair(rt, rt2, addr, op);
1763 } else {
1764 Register base = addr.base();
1765 if (addr.IsImmediateOffset()) {
1766 UseScratchRegisterScope temps(this);
1767 Register temp = temps.AcquireSameSizeAs(base);
1768 Add(temp, base, offset);
1769 LoadStorePair(rt, rt2, MemOperand(temp), op);
1770 } else if (addr.IsPostIndex()) {
1771 LoadStorePair(rt, rt2, MemOperand(base), op);
1772 Add(base, base, offset);
1773 } else {
1774 VIXL_ASSERT(addr.IsPreIndex());
1775 Add(base, base, offset);
1776 LoadStorePair(rt, rt2, MemOperand(base), op);
1777 }
1778 }
1779}
1780
armvixl330dc712014-11-25 10:38:32 +00001781
1782void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
1783 MacroEmissionCheckScope guard(this);
1784
1785 // There are no pre- or post-index modes for prfm.
1786 VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
1787
1788 // The access size is implicitly 8 bytes for all prefetch operations.
armvixl5289c592015-03-02 13:52:04 +00001789 unsigned size = kXRegSizeInBytesLog2;
armvixl330dc712014-11-25 10:38:32 +00001790
1791 // Check if an immediate offset fits in the immediate field of the
1792 // appropriate instruction. If not, emit two instructions to perform
1793 // the operation.
1794 if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.offset(), size) &&
1795 !IsImmLSUnscaled(addr.offset())) {
1796 // Immediate offset that can't be encoded using unsigned or unscaled
1797 // addressing modes.
1798 UseScratchRegisterScope temps(this);
1799 Register temp = temps.AcquireSameSizeAs(addr.base());
1800 Mov(temp, addr.offset());
1801 Prefetch(op, MemOperand(addr.base(), temp));
1802 } else {
1803 // Simple register-offsets are encodable in one instruction.
1804 Prefetch(op, addr);
1805 }
1806}
1807
1808
armvixl0f35e362016-05-10 13:57:58 +01001809void MacroAssembler::Push(const CPURegister& src0,
1810 const CPURegister& src1,
1811 const CPURegister& src2,
1812 const CPURegister& src3) {
armvixlb0c8ae22014-03-21 14:03:59 +00001813 VIXL_ASSERT(allow_macro_instructions_);
1814 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1815 VIXL_ASSERT(src0.IsValid());
armvixlad96eda2013-06-14 11:42:37 +01001816
1817 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
1818 int size = src0.SizeInBytes();
1819
1820 PrepareForPush(count, size);
1821 PushHelper(count, size, src0, src1, src2, src3);
1822}
1823
1824
armvixl0f35e362016-05-10 13:57:58 +01001825void MacroAssembler::Pop(const CPURegister& dst0,
1826 const CPURegister& dst1,
1827 const CPURegister& dst2,
1828 const CPURegister& dst3) {
armvixlad96eda2013-06-14 11:42:37 +01001829 // It is not valid to pop into the same register more than once in one
1830 // instruction, not even into the zero register.
armvixlb0c8ae22014-03-21 14:03:59 +00001831 VIXL_ASSERT(allow_macro_instructions_);
1832 VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
1833 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1834 VIXL_ASSERT(dst0.IsValid());
armvixlad96eda2013-06-14 11:42:37 +01001835
1836 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
1837 int size = dst0.SizeInBytes();
1838
1839 PrepareForPop(count, size);
1840 PopHelper(count, size, dst0, dst1, dst2, dst3);
1841}
1842
1843
1844void MacroAssembler::PushCPURegList(CPURegList registers) {
armvixl6e2c8272015-03-31 11:04:14 +01001845 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1846 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
armvixlb0c8ae22014-03-21 14:03:59 +00001847 VIXL_ASSERT(allow_macro_instructions_);
armvixl6e2c8272015-03-31 11:04:14 +01001848
1849 int reg_size = registers.RegisterSizeInBytes();
1850 PrepareForPush(registers.Count(), reg_size);
1851
1852 // Bump the stack pointer and store two registers at the bottom.
1853 int size = registers.TotalSizeInBytes();
1854 const CPURegister& bottom_0 = registers.PopLowestIndex();
1855 const CPURegister& bottom_1 = registers.PopLowestIndex();
1856 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1857 Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
1858 } else if (bottom_0.IsValid()) {
1859 Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
1860 }
1861
1862 int offset = 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001863 while (!registers.IsEmpty()) {
armvixl6e2c8272015-03-31 11:04:14 +01001864 const CPURegister& src0 = registers.PopLowestIndex();
1865 const CPURegister& src1 = registers.PopLowestIndex();
1866 if (src1.IsValid()) {
1867 Stp(src0, src1, MemOperand(StackPointer(), offset));
1868 } else {
1869 Str(src0, MemOperand(StackPointer(), offset));
1870 }
1871 offset += 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001872 }
1873}
1874
1875
1876void MacroAssembler::PopCPURegList(CPURegList registers) {
armvixl6e2c8272015-03-31 11:04:14 +01001877 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1878 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
armvixlb0c8ae22014-03-21 14:03:59 +00001879 VIXL_ASSERT(allow_macro_instructions_);
armvixl6e2c8272015-03-31 11:04:14 +01001880
1881 int reg_size = registers.RegisterSizeInBytes();
1882 PrepareForPop(registers.Count(), reg_size);
1883
1884
1885 int size = registers.TotalSizeInBytes();
1886 const CPURegister& bottom_0 = registers.PopLowestIndex();
1887 const CPURegister& bottom_1 = registers.PopLowestIndex();
1888
1889 int offset = 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001890 while (!registers.IsEmpty()) {
armvixlad96eda2013-06-14 11:42:37 +01001891 const CPURegister& dst0 = registers.PopLowestIndex();
1892 const CPURegister& dst1 = registers.PopLowestIndex();
armvixl6e2c8272015-03-31 11:04:14 +01001893 if (dst1.IsValid()) {
1894 Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
1895 } else {
1896 Ldr(dst0, MemOperand(StackPointer(), offset));
1897 }
1898 offset += 2 * reg_size;
1899 }
1900
1901 // Load the two registers at the bottom and drop the stack pointer.
1902 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1903 Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
1904 } else if (bottom_0.IsValid()) {
1905 Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
armvixlad96eda2013-06-14 11:42:37 +01001906 }
1907}
1908
1909
1910void MacroAssembler::PushMultipleTimes(int count, Register src) {
armvixlb0c8ae22014-03-21 14:03:59 +00001911 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001912 int size = src.SizeInBytes();
1913
1914 PrepareForPush(count, size);
1915 // Push up to four registers at a time if possible because if the current
1916 // stack pointer is sp and the register size is 32, registers must be pushed
1917 // in blocks of four in order to maintain the 16-byte alignment for sp.
1918 while (count >= 4) {
1919 PushHelper(4, size, src, src, src, src);
1920 count -= 4;
1921 }
1922 if (count >= 2) {
1923 PushHelper(2, size, src, src, NoReg, NoReg);
1924 count -= 2;
1925 }
1926 if (count == 1) {
1927 PushHelper(1, size, src, NoReg, NoReg, NoReg);
1928 count -= 1;
1929 }
armvixlb0c8ae22014-03-21 14:03:59 +00001930 VIXL_ASSERT(count == 0);
armvixlad96eda2013-06-14 11:42:37 +01001931}
1932
1933
armvixl0f35e362016-05-10 13:57:58 +01001934void MacroAssembler::PushHelper(int count,
1935 int size,
armvixlad96eda2013-06-14 11:42:37 +01001936 const CPURegister& src0,
1937 const CPURegister& src1,
1938 const CPURegister& src2,
1939 const CPURegister& src3) {
1940 // Ensure that we don't unintentionally modify scratch or debug registers.
armvixlc68cb642014-09-25 18:49:30 +01001941 // Worst case for size is 2 stp.
armvixl0f35e362016-05-10 13:57:58 +01001942 InstructionAccurateScope scope(this,
1943 2,
armvixlc68cb642014-09-25 18:49:30 +01001944 InstructionAccurateScope::kMaximumSize);
armvixlad96eda2013-06-14 11:42:37 +01001945
armvixlb0c8ae22014-03-21 14:03:59 +00001946 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1947 VIXL_ASSERT(size == src0.SizeInBytes());
armvixlad96eda2013-06-14 11:42:37 +01001948
1949 // When pushing multiple registers, the store order is chosen such that
1950 // Push(a, b) is equivalent to Push(a) followed by Push(b).
1951 switch (count) {
1952 case 1:
armvixlb0c8ae22014-03-21 14:03:59 +00001953 VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001954 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
1955 break;
1956 case 2:
armvixlb0c8ae22014-03-21 14:03:59 +00001957 VIXL_ASSERT(src2.IsNone() && src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001958 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
1959 break;
1960 case 3:
armvixlb0c8ae22014-03-21 14:03:59 +00001961 VIXL_ASSERT(src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001962 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
1963 str(src0, MemOperand(StackPointer(), 2 * size));
1964 break;
1965 case 4:
1966 // Skip over 4 * size, then fill in the gap. This allows four W registers
1967 // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
1968 // all times.
1969 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
1970 stp(src1, src0, MemOperand(StackPointer(), 2 * size));
1971 break;
1972 default:
armvixlb0c8ae22014-03-21 14:03:59 +00001973 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +01001974 }
1975}
1976
1977
armvixl0f35e362016-05-10 13:57:58 +01001978void MacroAssembler::PopHelper(int count,
1979 int size,
armvixlad96eda2013-06-14 11:42:37 +01001980 const CPURegister& dst0,
1981 const CPURegister& dst1,
1982 const CPURegister& dst2,
1983 const CPURegister& dst3) {
1984 // Ensure that we don't unintentionally modify scratch or debug registers.
armvixlc68cb642014-09-25 18:49:30 +01001985 // Worst case for size is 2 ldp.
armvixl0f35e362016-05-10 13:57:58 +01001986 InstructionAccurateScope scope(this,
1987 2,
armvixlc68cb642014-09-25 18:49:30 +01001988 InstructionAccurateScope::kMaximumSize);
armvixlad96eda2013-06-14 11:42:37 +01001989
armvixlb0c8ae22014-03-21 14:03:59 +00001990 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1991 VIXL_ASSERT(size == dst0.SizeInBytes());
armvixlad96eda2013-06-14 11:42:37 +01001992
1993 // When popping multiple registers, the load order is chosen such that
1994 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
1995 switch (count) {
1996 case 1:
armvixlb0c8ae22014-03-21 14:03:59 +00001997 VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001998 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
1999 break;
2000 case 2:
armvixlb0c8ae22014-03-21 14:03:59 +00002001 VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002002 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
2003 break;
2004 case 3:
armvixlb0c8ae22014-03-21 14:03:59 +00002005 VIXL_ASSERT(dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002006 ldr(dst2, MemOperand(StackPointer(), 2 * size));
2007 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
2008 break;
2009 case 4:
2010 // Load the higher addresses first, then load the lower addresses and skip
2011 // the whole block in the second instruction. This allows four W registers
2012 // to be popped using sp, whilst maintaining 16-byte alignment for sp at
2013 // all times.
2014 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
2015 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
2016 break;
2017 default:
armvixlb0c8ae22014-03-21 14:03:59 +00002018 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +01002019 }
2020}
2021
2022
2023void MacroAssembler::PrepareForPush(int count, int size) {
2024 if (sp.Is(StackPointer())) {
2025 // If the current stack pointer is sp, then it must be aligned to 16 bytes
2026 // on entry and the total size of the specified registers must also be a
2027 // multiple of 16 bytes.
armvixlb0c8ae22014-03-21 14:03:59 +00002028 VIXL_ASSERT((count * size) % 16 == 0);
armvixlad96eda2013-06-14 11:42:37 +01002029 } else {
2030 // Even if the current stack pointer is not the system stack pointer (sp),
2031 // the system stack pointer will still be modified in order to comply with
2032 // ABI rules about accessing memory below the system stack pointer.
2033 BumpSystemStackPointer(count * size);
2034 }
2035}
2036
2037
2038void MacroAssembler::PrepareForPop(int count, int size) {
armvixldb644342015-07-21 11:37:10 +01002039 USE(count, size);
armvixlad96eda2013-06-14 11:42:37 +01002040 if (sp.Is(StackPointer())) {
2041 // If the current stack pointer is sp, then it must be aligned to 16 bytes
2042 // on entry and the total size of the specified registers must also be a
2043 // multiple of 16 bytes.
armvixlb0c8ae22014-03-21 14:03:59 +00002044 VIXL_ASSERT((count * size) % 16 == 0);
armvixlad96eda2013-06-14 11:42:37 +01002045 }
2046}
2047
2048void MacroAssembler::Poke(const Register& src, const Operand& offset) {
armvixlb0c8ae22014-03-21 14:03:59 +00002049 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002050 if (offset.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002051 VIXL_ASSERT(offset.immediate() >= 0);
armvixlad96eda2013-06-14 11:42:37 +01002052 }
2053
2054 Str(src, MemOperand(StackPointer(), offset));
2055}
2056
2057
2058void MacroAssembler::Peek(const Register& dst, const Operand& offset) {
armvixlb0c8ae22014-03-21 14:03:59 +00002059 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002060 if (offset.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002061 VIXL_ASSERT(offset.immediate() >= 0);
armvixlad96eda2013-06-14 11:42:37 +01002062 }
2063
2064 Ldr(dst, MemOperand(StackPointer(), offset));
2065}
2066
2067
2068void MacroAssembler::Claim(const Operand& size) {
armvixlb0c8ae22014-03-21 14:03:59 +00002069 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00002070
2071 if (size.IsZero()) {
2072 return;
2073 }
2074
armvixlad96eda2013-06-14 11:42:37 +01002075 if (size.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002076 VIXL_ASSERT(size.immediate() > 0);
armvixlad96eda2013-06-14 11:42:37 +01002077 if (sp.Is(StackPointer())) {
armvixlb0c8ae22014-03-21 14:03:59 +00002078 VIXL_ASSERT((size.immediate() % 16) == 0);
armvixlad96eda2013-06-14 11:42:37 +01002079 }
2080 }
2081
2082 if (!sp.Is(StackPointer())) {
2083 BumpSystemStackPointer(size);
2084 }
2085
2086 Sub(StackPointer(), StackPointer(), size);
2087}
2088
2089
2090void MacroAssembler::Drop(const Operand& size) {
armvixlb0c8ae22014-03-21 14:03:59 +00002091 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00002092
2093 if (size.IsZero()) {
2094 return;
2095 }
2096
armvixlad96eda2013-06-14 11:42:37 +01002097 if (size.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002098 VIXL_ASSERT(size.immediate() > 0);
armvixlad96eda2013-06-14 11:42:37 +01002099 if (sp.Is(StackPointer())) {
armvixlb0c8ae22014-03-21 14:03:59 +00002100 VIXL_ASSERT((size.immediate() % 16) == 0);
armvixlad96eda2013-06-14 11:42:37 +01002101 }
2102 }
2103
2104 Add(StackPointer(), StackPointer(), size);
2105}
2106
2107
2108void MacroAssembler::PushCalleeSavedRegisters() {
2109 // Ensure that the macro-assembler doesn't use any scratch registers.
armvixlc68cb642014-09-25 18:49:30 +01002110 // 10 stp will be emitted.
2111 // TODO(all): Should we use GetCalleeSaved and SavedFP.
2112 InstructionAccurateScope scope(this, 10);
armvixlad96eda2013-06-14 11:42:37 +01002113
2114 // This method must not be called unless the current stack pointer is sp.
armvixlb0c8ae22014-03-21 14:03:59 +00002115 VIXL_ASSERT(sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002116
armvixldb644342015-07-21 11:37:10 +01002117 MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);
armvixlad96eda2013-06-14 11:42:37 +01002118
armvixlad96eda2013-06-14 11:42:37 +01002119 stp(x29, x30, tos);
2120 stp(x27, x28, tos);
2121 stp(x25, x26, tos);
2122 stp(x23, x24, tos);
2123 stp(x21, x22, tos);
2124 stp(x19, x20, tos);
armvixl5799d6c2014-05-01 11:05:00 +01002125
2126 stp(d14, d15, tos);
2127 stp(d12, d13, tos);
2128 stp(d10, d11, tos);
2129 stp(d8, d9, tos);
armvixlad96eda2013-06-14 11:42:37 +01002130}
2131
2132
2133void MacroAssembler::PopCalleeSavedRegisters() {
2134 // Ensure that the macro-assembler doesn't use any scratch registers.
armvixlc68cb642014-09-25 18:49:30 +01002135 // 10 ldp will be emitted.
2136 // TODO(all): Should we use GetCalleeSaved and SavedFP.
2137 InstructionAccurateScope scope(this, 10);
armvixlad96eda2013-06-14 11:42:37 +01002138
2139 // This method must not be called unless the current stack pointer is sp.
armvixlb0c8ae22014-03-21 14:03:59 +00002140 VIXL_ASSERT(sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002141
2142 MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
2143
armvixl5799d6c2014-05-01 11:05:00 +01002144 ldp(d8, d9, tos);
2145 ldp(d10, d11, tos);
2146 ldp(d12, d13, tos);
2147 ldp(d14, d15, tos);
2148
armvixlad96eda2013-06-14 11:42:37 +01002149 ldp(x19, x20, tos);
2150 ldp(x21, x22, tos);
2151 ldp(x23, x24, tos);
2152 ldp(x25, x26, tos);
2153 ldp(x27, x28, tos);
2154 ldp(x29, x30, tos);
armvixlad96eda2013-06-14 11:42:37 +01002155}
2156
armvixl6e2c8272015-03-31 11:04:14 +01002157void MacroAssembler::LoadCPURegList(CPURegList registers,
2158 const MemOperand& src) {
2159 LoadStoreCPURegListHelper(kLoad, registers, src);
2160}
2161
2162void MacroAssembler::StoreCPURegList(CPURegList registers,
2163 const MemOperand& dst) {
2164 LoadStoreCPURegListHelper(kStore, registers, dst);
2165}
2166
2167
2168void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
2169 CPURegList registers,
2170 const MemOperand& mem) {
2171 // We do not handle pre-indexing or post-indexing.
2172 VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
2173 VIXL_ASSERT(!registers.Overlaps(tmp_list_));
2174 VIXL_ASSERT(!registers.Overlaps(fptmp_list_));
2175 VIXL_ASSERT(!registers.IncludesAliasOf(sp));
2176
2177 UseScratchRegisterScope temps(this);
2178
armvixl0f35e362016-05-10 13:57:58 +01002179 MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers, mem, &temps);
armvixl6e2c8272015-03-31 11:04:14 +01002180
2181 while (registers.Count() >= 2) {
2182 const CPURegister& dst0 = registers.PopLowestIndex();
2183 const CPURegister& dst1 = registers.PopLowestIndex();
2184 if (op == kStore) {
2185 Stp(dst0, dst1, loc);
2186 } else {
2187 VIXL_ASSERT(op == kLoad);
2188 Ldp(dst0, dst1, loc);
2189 }
2190 loc.AddOffset(2 * registers.RegisterSizeInBytes());
2191 }
2192 if (!registers.IsEmpty()) {
2193 if (op == kStore) {
2194 Str(registers.PopLowestIndex(), loc);
2195 } else {
2196 VIXL_ASSERT(op == kLoad);
2197 Ldr(registers.PopLowestIndex(), loc);
2198 }
2199 }
2200}
2201
2202MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
2203 const CPURegList& registers,
2204 const MemOperand& mem,
2205 UseScratchRegisterScope* scratch_scope) {
2206 // If necessary, pre-compute the base address for the accesses.
2207 if (mem.IsRegisterOffset()) {
2208 Register reg_base = scratch_scope->AcquireX();
2209 ComputeAddress(reg_base, mem);
2210 return MemOperand(reg_base);
2211
2212 } else if (mem.IsImmediateOffset()) {
2213 int reg_size = registers.RegisterSizeInBytes();
2214 int total_size = registers.TotalSizeInBytes();
2215 int64_t min_offset = mem.offset();
2216 int64_t max_offset = mem.offset() + std::max(0, total_size - 2 * reg_size);
2217 if ((registers.Count() >= 2) &&
2218 (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
2219 !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
2220 Register reg_base = scratch_scope->AcquireX();
2221 ComputeAddress(reg_base, mem);
2222 return MemOperand(reg_base);
2223 }
2224 }
2225
2226 return mem;
2227}
2228
armvixlad96eda2013-06-14 11:42:37 +01002229void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
armvixlb0c8ae22014-03-21 14:03:59 +00002230 VIXL_ASSERT(!sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002231 // TODO: Several callers rely on this not using scratch registers, so we use
2232 // the assembler directly here. However, this means that large immediate
2233 // values of 'space' cannot be handled.
armvixlc68cb642014-09-25 18:49:30 +01002234 InstructionAccurateScope scope(this, 1);
armvixlad96eda2013-06-14 11:42:37 +01002235 sub(sp, StackPointer(), space);
2236}
2237
2238
armvixl5289c592015-03-02 13:52:04 +00002239// TODO(all): Fix printf for NEON registers, and resolve whether we should be
2240// using FPRegister or VRegister here.
2241
armvixlad96eda2013-06-14 11:42:37 +01002242// This is the main Printf implementation. All callee-saved registers are
2243// preserved, but NZCV and the caller-saved registers may be clobbered.
armvixl0f35e362016-05-10 13:57:58 +01002244void MacroAssembler::PrintfNoPreserve(const char* format,
armvixlad96eda2013-06-14 11:42:37 +01002245 const CPURegister& arg0,
2246 const CPURegister& arg1,
2247 const CPURegister& arg2,
2248 const CPURegister& arg3) {
2249 // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2250 // in most cases anyway, so this restriction shouldn't be too serious.
armvixlb0c8ae22014-03-21 14:03:59 +00002251 VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002252
armvixl5799d6c2014-05-01 11:05:00 +01002253 // The provided arguments, and their proper PCS registers.
2254 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
2255 CPURegister pcs[kPrintfMaxArgCount];
2256
2257 int arg_count = kPrintfMaxArgCount;
2258
2259 // The PCS varargs registers for printf. Note that x0 is used for the printf
2260 // format string.
2261 static const CPURegList kPCSVarargs =
2262 CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
2263 static const CPURegList kPCSVarargsFP =
armvixl5289c592015-03-02 13:52:04 +00002264 CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
armvixl5799d6c2014-05-01 11:05:00 +01002265
2266 // We can use caller-saved registers as scratch values, except for the
2267 // arguments and the PCS registers where they might need to go.
armvixlb0c8ae22014-03-21 14:03:59 +00002268 UseScratchRegisterScope temps(this);
armvixl5799d6c2014-05-01 11:05:00 +01002269 temps.Include(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002270 temps.Include(kCallerSavedV);
armvixl5799d6c2014-05-01 11:05:00 +01002271 temps.Exclude(kPCSVarargs);
2272 temps.Exclude(kPCSVarargsFP);
armvixlb0c8ae22014-03-21 14:03:59 +00002273 temps.Exclude(arg0, arg1, arg2, arg3);
2274
armvixl5799d6c2014-05-01 11:05:00 +01002275 // Copies of the arg lists that we can iterate through.
2276 CPURegList pcs_varargs = kPCSVarargs;
2277 CPURegList pcs_varargs_fp = kPCSVarargsFP;
armvixlad96eda2013-06-14 11:42:37 +01002278
armvixl5799d6c2014-05-01 11:05:00 +01002279 // Place the arguments. There are lots of clever tricks and optimizations we
2280 // could use here, but Printf is a debug tool so instead we just try to keep
2281 // it simple: Move each input that isn't already in the right place to a
2282 // scratch register, then move everything back.
2283 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
2284 // Work out the proper PCS register for this argument.
armvixlad96eda2013-06-14 11:42:37 +01002285 if (args[i].IsRegister()) {
armvixl5799d6c2014-05-01 11:05:00 +01002286 pcs[i] = pcs_varargs.PopLowestIndex().X();
2287 // We might only need a W register here. We need to know the size of the
2288 // argument so we can properly encode it for the simulator call.
2289 if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
armvixl5289c592015-03-02 13:52:04 +00002290 } else if (args[i].IsVRegister()) {
armvixl5799d6c2014-05-01 11:05:00 +01002291 // In C, floats are always cast to doubles for varargs calls.
2292 pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
armvixlad96eda2013-06-14 11:42:37 +01002293 } else {
armvixl5799d6c2014-05-01 11:05:00 +01002294 VIXL_ASSERT(args[i].IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002295 arg_count = i;
2296 break;
2297 }
armvixlad96eda2013-06-14 11:42:37 +01002298
armvixl5799d6c2014-05-01 11:05:00 +01002299 // If the argument is already in the right place, leave it where it is.
2300 if (args[i].Aliases(pcs[i])) continue;
armvixlad96eda2013-06-14 11:42:37 +01002301
armvixl5799d6c2014-05-01 11:05:00 +01002302 // Otherwise, if the argument is in a PCS argument register, allocate an
2303 // appropriate scratch register and then move it out of the way.
2304 if (kPCSVarargs.IncludesAliasOf(args[i]) ||
2305 kPCSVarargsFP.IncludesAliasOf(args[i])) {
2306 if (args[i].IsRegister()) {
2307 Register old_arg = Register(args[i]);
2308 Register new_arg = temps.AcquireSameSizeAs(old_arg);
2309 Mov(new_arg, old_arg);
2310 args[i] = new_arg;
2311 } else {
2312 FPRegister old_arg = FPRegister(args[i]);
2313 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
2314 Fmov(new_arg, old_arg);
2315 args[i] = new_arg;
2316 }
armvixlad96eda2013-06-14 11:42:37 +01002317 }
2318 }
2319
armvixl5799d6c2014-05-01 11:05:00 +01002320 // Do a second pass to move values into their final positions and perform any
2321 // conversions that may be required.
2322 for (int i = 0; i < arg_count; i++) {
2323 VIXL_ASSERT(pcs[i].type() == args[i].type());
2324 if (pcs[i].IsRegister()) {
2325 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2326 } else {
armvixl5289c592015-03-02 13:52:04 +00002327 VIXL_ASSERT(pcs[i].IsVRegister());
armvixl5799d6c2014-05-01 11:05:00 +01002328 if (pcs[i].size() == args[i].size()) {
2329 Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
2330 } else {
2331 Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
2332 }
2333 }
armvixlad96eda2013-06-14 11:42:37 +01002334 }
2335
2336 // Load the format string into x0, as per the procedure-call standard.
2337 //
2338 // To make the code as portable as possible, the format string is encoded
2339 // directly in the instruction stream. It might be cleaner to encode it in a
2340 // literal pool, but since Printf is usually used for debugging, it is
2341 // beneficial for it to be minimally dependent on other features.
armvixl5799d6c2014-05-01 11:05:00 +01002342 temps.Exclude(x0);
armvixlad96eda2013-06-14 11:42:37 +01002343 Label format_address;
2344 Adr(x0, &format_address);
2345
2346 // Emit the format string directly in the instruction stream.
armvixlc68cb642014-09-25 18:49:30 +01002347 {
armvixl5289c592015-03-02 13:52:04 +00002348 BlockPoolsScope scope(this);
armvixlc68cb642014-09-25 18:49:30 +01002349 // Data emitted:
2350 // branch
2351 // strlen(format) + 1 (includes null termination)
2352 // padding to next instruction
2353 // unreachable
armvixl0f35e362016-05-10 13:57:58 +01002354 EmissionCheckScope guard(this,
2355 AlignUp(strlen(format) + 1, kInstructionSize) +
2356 2 * kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002357 Label after_data;
2358 B(&after_data);
2359 Bind(&format_address);
armvixlc68cb642014-09-25 18:49:30 +01002360 EmitString(format);
armvixlad96eda2013-06-14 11:42:37 +01002361 Unreachable();
2362 Bind(&after_data);
2363 }
2364
2365 // We don't pass any arguments on the stack, but we still need to align the C
2366 // stack pointer to a 16-byte boundary for PCS compliance.
2367 if (!sp.Is(StackPointer())) {
2368 Bic(sp, StackPointer(), 0xf);
2369 }
2370
2371 // Actually call printf. This part needs special handling for the simulator,
2372 // since the system printf function will use a different instruction set and
2373 // the procedure-call standard will not be compatible.
armvixl684cd2a2015-10-23 13:38:33 +01002374 if (allow_simulator_instructions_) {
armvixlc68cb642014-09-25 18:49:30 +01002375 InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002376 hlt(kPrintfOpcode);
armvixl0f35e362016-05-10 13:57:58 +01002377 dc32(arg_count); // kPrintfArgCountOffset
armvixl5799d6c2014-05-01 11:05:00 +01002378
2379 // Determine the argument pattern.
2380 uint32_t arg_pattern_list = 0;
2381 for (int i = 0; i < arg_count; i++) {
2382 uint32_t arg_pattern;
2383 if (pcs[i].IsRegister()) {
2384 arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
2385 } else {
2386 VIXL_ASSERT(pcs[i].Is64Bits());
2387 arg_pattern = kPrintfArgD;
2388 }
2389 VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
2390 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
2391 }
armvixl0f35e362016-05-10 13:57:58 +01002392 dc32(arg_pattern_list); // kPrintfArgPatternListOffset
armvixl684cd2a2015-10-23 13:38:33 +01002393 } else {
2394 Register tmp = temps.AcquireX();
2395 Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2396 Blr(tmp);
armvixlad96eda2013-06-14 11:42:37 +01002397 }
armvixlad96eda2013-06-14 11:42:37 +01002398}
2399
2400
armvixl0f35e362016-05-10 13:57:58 +01002401void MacroAssembler::Printf(const char* format,
armvixl5799d6c2014-05-01 11:05:00 +01002402 CPURegister arg0,
2403 CPURegister arg1,
2404 CPURegister arg2,
2405 CPURegister arg3) {
2406 // We can only print sp if it is the current stack pointer.
2407 if (!sp.Is(StackPointer())) {
2408 VIXL_ASSERT(!sp.Aliases(arg0));
2409 VIXL_ASSERT(!sp.Aliases(arg1));
2410 VIXL_ASSERT(!sp.Aliases(arg2));
2411 VIXL_ASSERT(!sp.Aliases(arg3));
2412 }
2413
armvixlb0c8ae22014-03-21 14:03:59 +00002414 // Make sure that the macro assembler doesn't try to use any of our arguments
2415 // as scratch registers.
2416 UseScratchRegisterScope exclude_all(this);
2417 exclude_all.ExcludeAll();
2418
armvixlad96eda2013-06-14 11:42:37 +01002419 // Preserve all caller-saved registers as well as NZCV.
2420 // If sp is the stack pointer, PushCPURegList asserts that the size of each
2421 // list is a multiple of 16 bytes.
2422 PushCPURegList(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002423 PushCPURegList(kCallerSavedV);
armvixlad96eda2013-06-14 11:42:37 +01002424
armvixl0f35e362016-05-10 13:57:58 +01002425 {
2426 UseScratchRegisterScope temps(this);
armvixlb0c8ae22014-03-21 14:03:59 +00002427 // We can use caller-saved registers as scratch values (except for argN).
armvixl5799d6c2014-05-01 11:05:00 +01002428 temps.Include(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002429 temps.Include(kCallerSavedV);
armvixlb0c8ae22014-03-21 14:03:59 +00002430 temps.Exclude(arg0, arg1, arg2, arg3);
armvixlad96eda2013-06-14 11:42:37 +01002431
armvixl5799d6c2014-05-01 11:05:00 +01002432 // If any of the arguments are the current stack pointer, allocate a new
2433 // register for them, and adjust the value to compensate for pushing the
2434 // caller-saved registers.
2435 bool arg0_sp = StackPointer().Aliases(arg0);
2436 bool arg1_sp = StackPointer().Aliases(arg1);
2437 bool arg2_sp = StackPointer().Aliases(arg2);
2438 bool arg3_sp = StackPointer().Aliases(arg3);
2439 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
2440 // Allocate a register to hold the original stack pointer value, to pass
2441 // to PrintfNoPreserve as an argument.
2442 Register arg_sp = temps.AcquireX();
armvixl0f35e362016-05-10 13:57:58 +01002443 Add(arg_sp,
2444 StackPointer(),
armvixl5289c592015-03-02 13:52:04 +00002445 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes());
armvixl5799d6c2014-05-01 11:05:00 +01002446 if (arg0_sp) arg0 = Register(arg_sp.code(), arg0.size());
2447 if (arg1_sp) arg1 = Register(arg_sp.code(), arg1.size());
2448 if (arg2_sp) arg2 = Register(arg_sp.code(), arg2.size());
2449 if (arg3_sp) arg3 = Register(arg_sp.code(), arg3.size());
2450 }
2451
armvixlb0c8ae22014-03-21 14:03:59 +00002452 // Preserve NZCV.
2453 Register tmp = temps.AcquireX();
2454 Mrs(tmp, NZCV);
2455 Push(tmp, xzr);
armvixl5799d6c2014-05-01 11:05:00 +01002456 temps.Release(tmp);
armvixlb0c8ae22014-03-21 14:03:59 +00002457
2458 PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2459
armvixl5799d6c2014-05-01 11:05:00 +01002460 // Restore NZCV.
2461 tmp = temps.AcquireX();
armvixlb0c8ae22014-03-21 14:03:59 +00002462 Pop(xzr, tmp);
2463 Msr(NZCV, tmp);
armvixl5799d6c2014-05-01 11:05:00 +01002464 temps.Release(tmp);
armvixlb0c8ae22014-03-21 14:03:59 +00002465 }
2466
armvixl5289c592015-03-02 13:52:04 +00002467 PopCPURegList(kCallerSavedV);
armvixlad96eda2013-06-14 11:42:37 +01002468 PopCPURegList(kCallerSaved);
2469}
2470
2471void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
armvixlb0c8ae22014-03-21 14:03:59 +00002472 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002473
armvixl684cd2a2015-10-23 13:38:33 +01002474 if (allow_simulator_instructions_) {
2475 // The arguments to the trace pseudo instruction need to be contiguous in
2476 // memory, so make sure we don't try to emit a literal pool.
2477 InstructionAccurateScope scope(this, kTraceLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002478
armvixl684cd2a2015-10-23 13:38:33 +01002479 Label start;
2480 bind(&start);
armvixlad96eda2013-06-14 11:42:37 +01002481
armvixl684cd2a2015-10-23 13:38:33 +01002482 // Refer to simulator-a64.h for a description of the marker and its
2483 // arguments.
2484 hlt(kTraceOpcode);
armvixlad96eda2013-06-14 11:42:37 +01002485
armvixl684cd2a2015-10-23 13:38:33 +01002486 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2487 dc32(parameters);
armvixlad96eda2013-06-14 11:42:37 +01002488
armvixl684cd2a2015-10-23 13:38:33 +01002489 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2490 dc32(command);
2491 } else {
2492 // Emit nothing on real hardware.
2493 USE(parameters, command);
2494 }
armvixlad96eda2013-06-14 11:42:37 +01002495}
2496
2497
2498void MacroAssembler::Log(TraceParameters parameters) {
armvixlb0c8ae22014-03-21 14:03:59 +00002499 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002500
armvixl684cd2a2015-10-23 13:38:33 +01002501 if (allow_simulator_instructions_) {
2502 // The arguments to the log pseudo instruction need to be contiguous in
2503 // memory, so make sure we don't try to emit a literal pool.
2504 InstructionAccurateScope scope(this, kLogLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002505
armvixl684cd2a2015-10-23 13:38:33 +01002506 Label start;
2507 bind(&start);
armvixlad96eda2013-06-14 11:42:37 +01002508
armvixl684cd2a2015-10-23 13:38:33 +01002509 // Refer to simulator-a64.h for a description of the marker and its
2510 // arguments.
2511 hlt(kLogOpcode);
armvixlad96eda2013-06-14 11:42:37 +01002512
armvixl684cd2a2015-10-23 13:38:33 +01002513 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2514 dc32(parameters);
2515 } else {
2516 // Emit nothing on real hardware.
2517 USE(parameters);
2518 }
armvixlad96eda2013-06-14 11:42:37 +01002519}
2520
armvixl578645f2013-08-15 17:21:42 +01002521
2522void MacroAssembler::EnableInstrumentation() {
armvixlb0c8ae22014-03-21 14:03:59 +00002523 VIXL_ASSERT(!isprint(InstrumentStateEnable));
armvixl578645f2013-08-15 17:21:42 +01002524 InstructionAccurateScope scope(this, 1);
2525 movn(xzr, InstrumentStateEnable);
2526}
2527
2528
2529void MacroAssembler::DisableInstrumentation() {
armvixlb0c8ae22014-03-21 14:03:59 +00002530 VIXL_ASSERT(!isprint(InstrumentStateDisable));
armvixl578645f2013-08-15 17:21:42 +01002531 InstructionAccurateScope scope(this, 1);
2532 movn(xzr, InstrumentStateDisable);
2533}
2534
2535
2536void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
armvixlb0c8ae22014-03-21 14:03:59 +00002537 VIXL_ASSERT(strlen(marker_name) == 2);
armvixl578645f2013-08-15 17:21:42 +01002538
2539 // We allow only printable characters in the marker names. Unprintable
2540 // characters are reserved for controlling features of the instrumentation.
armvixlb0c8ae22014-03-21 14:03:59 +00002541 VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
armvixl578645f2013-08-15 17:21:42 +01002542
2543 InstructionAccurateScope scope(this, 1);
2544 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
2545}
2546
armvixlb0c8ae22014-03-21 14:03:59 +00002547
armvixl330dc712014-11-25 10:38:32 +00002548void UseScratchRegisterScope::Open(MacroAssembler* masm) {
2549 VIXL_ASSERT(!initialised_);
armvixl0f35e362016-05-10 13:57:58 +01002550 VIXL_ASSERT(masm != NULL);
armvixl330dc712014-11-25 10:38:32 +00002551 available_ = masm->TmpList();
2552 availablefp_ = masm->FPTmpList();
2553 old_available_ = available_->list();
2554 old_availablefp_ = availablefp_->list();
2555 VIXL_ASSERT(available_->type() == CPURegister::kRegister);
armvixl5289c592015-03-02 13:52:04 +00002556 VIXL_ASSERT(availablefp_->type() == CPURegister::kVRegister);
armvixl330dc712014-11-25 10:38:32 +00002557#ifdef VIXL_DEBUG
2558 initialised_ = true;
2559#endif
2560}
2561
2562
2563void UseScratchRegisterScope::Close() {
2564 if (available_) {
2565 available_->set_list(old_available_);
2566 available_ = NULL;
2567 }
2568 if (availablefp_) {
2569 availablefp_->set_list(old_availablefp_);
2570 availablefp_ = NULL;
2571 }
2572#ifdef VIXL_DEBUG
2573 initialised_ = false;
2574#endif
2575}
2576
2577
2578UseScratchRegisterScope::UseScratchRegisterScope(MacroAssembler* masm) {
2579#ifdef VIXL_DEBUG
2580 initialised_ = false;
2581#endif
2582 Open(masm);
2583}
2584
2585// This allows deferred (and optional) initialisation of the scope.
2586UseScratchRegisterScope::UseScratchRegisterScope()
armvixl0f35e362016-05-10 13:57:58 +01002587 : available_(NULL),
2588 availablefp_(NULL),
2589 old_available_(0),
2590 old_availablefp_(0) {
armvixl330dc712014-11-25 10:38:32 +00002591#ifdef VIXL_DEBUG
2592 initialised_ = false;
2593#endif
2594}
2595
armvixl0f35e362016-05-10 13:57:58 +01002596UseScratchRegisterScope::~UseScratchRegisterScope() { Close(); }
armvixlb0c8ae22014-03-21 14:03:59 +00002597
2598
armvixl5799d6c2014-05-01 11:05:00 +01002599bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2600 return available_->IncludesAliasOf(reg) || availablefp_->IncludesAliasOf(reg);
2601}
2602
2603
armvixlb0c8ae22014-03-21 14:03:59 +00002604Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
2605 int code = AcquireNextAvailable(available_).code();
armvixl4a102ba2014-07-14 09:02:40 +01002606 return Register(code, reg.size());
armvixlb0c8ae22014-03-21 14:03:59 +00002607}
2608
2609
2610FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
2611 int code = AcquireNextAvailable(availablefp_).code();
armvixl4a102ba2014-07-14 09:02:40 +01002612 return FPRegister(code, reg.size());
armvixlb0c8ae22014-03-21 14:03:59 +00002613}
2614
2615
2616void UseScratchRegisterScope::Release(const CPURegister& reg) {
armvixl330dc712014-11-25 10:38:32 +00002617 VIXL_ASSERT(initialised_);
armvixlb0c8ae22014-03-21 14:03:59 +00002618 if (reg.IsRegister()) {
2619 ReleaseByCode(available_, reg.code());
2620 } else if (reg.IsFPRegister()) {
2621 ReleaseByCode(availablefp_, reg.code());
2622 } else {
2623 VIXL_ASSERT(reg.IsNone());
2624 }
2625}
2626
2627
armvixl5799d6c2014-05-01 11:05:00 +01002628void UseScratchRegisterScope::Include(const CPURegList& list) {
armvixl330dc712014-11-25 10:38:32 +00002629 VIXL_ASSERT(initialised_);
armvixl5799d6c2014-05-01 11:05:00 +01002630 if (list.type() == CPURegister::kRegister) {
2631 // Make sure that neither sp nor xzr are included the list.
2632 IncludeByRegList(available_, list.list() & ~(xzr.Bit() | sp.Bit()));
2633 } else {
armvixl5289c592015-03-02 13:52:04 +00002634 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
armvixl5799d6c2014-05-01 11:05:00 +01002635 IncludeByRegList(availablefp_, list.list());
2636 }
2637}
2638
2639
armvixlb0c8ae22014-03-21 14:03:59 +00002640void UseScratchRegisterScope::Include(const Register& reg1,
2641 const Register& reg2,
2642 const Register& reg3,
2643 const Register& reg4) {
armvixl330dc712014-11-25 10:38:32 +00002644 VIXL_ASSERT(initialised_);
armvixlb0c8ae22014-03-21 14:03:59 +00002645 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2646 // Make sure that neither sp nor xzr are included the list.
2647 include &= ~(xzr.Bit() | sp.Bit());
2648
2649 IncludeByRegList(available_, include);
2650}
2651
2652
2653void UseScratchRegisterScope::Include(const FPRegister& reg1,
2654 const FPRegister& reg2,
2655 const FPRegister& reg3,
2656 const FPRegister& reg4) {
2657 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2658 IncludeByRegList(availablefp_, include);
2659}
2660
2661
armvixl5799d6c2014-05-01 11:05:00 +01002662void UseScratchRegisterScope::Exclude(const CPURegList& list) {
2663 if (list.type() == CPURegister::kRegister) {
2664 ExcludeByRegList(available_, list.list());
2665 } else {
armvixl5289c592015-03-02 13:52:04 +00002666 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
armvixl5799d6c2014-05-01 11:05:00 +01002667 ExcludeByRegList(availablefp_, list.list());
2668 }
2669}
2670
2671
armvixlb0c8ae22014-03-21 14:03:59 +00002672void UseScratchRegisterScope::Exclude(const Register& reg1,
2673 const Register& reg2,
2674 const Register& reg3,
2675 const Register& reg4) {
2676 RegList exclude = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2677 ExcludeByRegList(available_, exclude);
2678}
2679
2680
2681void UseScratchRegisterScope::Exclude(const FPRegister& reg1,
2682 const FPRegister& reg2,
2683 const FPRegister& reg3,
2684 const FPRegister& reg4) {
2685 RegList excludefp = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2686 ExcludeByRegList(availablefp_, excludefp);
2687}
2688
2689
2690void UseScratchRegisterScope::Exclude(const CPURegister& reg1,
2691 const CPURegister& reg2,
2692 const CPURegister& reg3,
2693 const CPURegister& reg4) {
2694 RegList exclude = 0;
2695 RegList excludefp = 0;
2696
2697 const CPURegister regs[] = {reg1, reg2, reg3, reg4};
2698
2699 for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
2700 if (regs[i].IsRegister()) {
2701 exclude |= regs[i].Bit();
2702 } else if (regs[i].IsFPRegister()) {
2703 excludefp |= regs[i].Bit();
2704 } else {
2705 VIXL_ASSERT(regs[i].IsNone());
2706 }
2707 }
2708
2709 ExcludeByRegList(available_, exclude);
2710 ExcludeByRegList(availablefp_, excludefp);
2711}
2712
2713
2714void UseScratchRegisterScope::ExcludeAll() {
2715 ExcludeByRegList(available_, available_->list());
2716 ExcludeByRegList(availablefp_, availablefp_->list());
2717}
2718
2719
2720CPURegister UseScratchRegisterScope::AcquireNextAvailable(
2721 CPURegList* available) {
2722 VIXL_CHECK(!available->IsEmpty());
2723 CPURegister result = available->PopLowestIndex();
2724 VIXL_ASSERT(!AreAliased(result, xzr, sp));
2725 return result;
2726}
2727
2728
2729void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
2730 ReleaseByRegList(available, static_cast<RegList>(1) << code);
2731}
2732
2733
2734void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
2735 RegList regs) {
2736 available->set_list(available->list() | regs);
2737}
2738
2739
2740void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
2741 RegList regs) {
2742 available->set_list(available->list() | regs);
2743}
2744
2745
2746void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
2747 RegList exclude) {
2748 available->set_list(available->list() & ~exclude);
2749}
2750
armvixlad96eda2013-06-14 11:42:37 +01002751} // namespace vixl