blob: 5681d4ad73fd5c1e07633caf6036162b097ccd37 [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
1286 if ((left == 0) && (right == 1)) {
1287 if (emit_code) masm->cset(rd, cond);
1288 return true;
1289 } else if ((left == 0) && (right == -1)) {
1290 Register zr = AppropriateZeroRegFor(rd);
1291 if (emit_code) masm->csinv(rd, zr, zr, InvertCondition(cond));
1292 return true;
1293 }
1294 return false;
1295}
1296
1297
1298void MacroAssembler::CselSubHelperRightSmallImmediate(
1299 MacroAssembler* masm,
1300 UseScratchRegisterScope* temps,
1301 const Register& rd,
1302 const Operand& left,
1303 const Operand& right,
1304 Condition cond,
1305 bool* should_synthesise_left) {
1306 bool emit_code = (masm != NULL);
1307 VIXL_ASSERT((right.IsImmediate() || right.IsZero()) &&
1308 (-1 <= right.GetEquivalentImmediate()) &&
1309 (right.GetEquivalentImmediate() <= 1));
1310 Register left_register;
1311
1312 if (left.IsPlainRegister()) {
1313 left_register = left.reg();
1314 } else {
1315 if (emit_code) {
1316 left_register = temps->AcquireSameSizeAs(rd);
1317 masm->Mov(left_register, left);
1318 }
1319 if (should_synthesise_left != NULL) *should_synthesise_left = true;
1320 }
1321 if (emit_code) {
1322 int64_t imm = right.GetEquivalentImmediate();
1323 Register zr = AppropriateZeroRegFor(rd);
1324 if (imm == 0) {
1325 masm->csel(rd, left_register, zr, cond);
1326 } else if (imm == 1) {
1327 masm->csinc(rd, left_register, zr, cond);
1328 } else {
1329 VIXL_ASSERT(imm == -1);
1330 masm->csinv(rd, left_register, zr, cond);
1331 }
armvixlad96eda2013-06-14 11:42:37 +01001332 }
1333}
1334
1335
1336void MacroAssembler::Add(const Register& rd,
1337 const Register& rn,
armvixl6e2c8272015-03-31 11:04:14 +01001338 const Operand& operand,
1339 FlagsUpdate S) {
armvixlb0c8ae22014-03-21 14:03:59 +00001340 VIXL_ASSERT(allow_macro_instructions_);
armvixl4a102ba2014-07-14 09:02:40 +01001341 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1342 IsImmAddSub(-operand.immediate())) {
armvixl6e2c8272015-03-31 11:04:14 +01001343 AddSubMacro(rd, rn, -operand.immediate(), S, SUB);
armvixlad96eda2013-06-14 11:42:37 +01001344 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001345 AddSubMacro(rd, rn, operand, S, ADD);
armvixlf37fdc02014-02-05 13:22:16 +00001346 }
1347}
1348
1349
1350void MacroAssembler::Adds(const Register& rd,
1351 const Register& rn,
1352 const Operand& operand) {
armvixl6e2c8272015-03-31 11:04:14 +01001353 Add(rd, rn, operand, SetFlags);
armvixlad96eda2013-06-14 11:42:37 +01001354}
1355
1356
1357void MacroAssembler::Sub(const Register& rd,
1358 const Register& rn,
armvixl6e2c8272015-03-31 11:04:14 +01001359 const Operand& operand,
1360 FlagsUpdate S) {
armvixlb0c8ae22014-03-21 14:03:59 +00001361 VIXL_ASSERT(allow_macro_instructions_);
armvixl4a102ba2014-07-14 09:02:40 +01001362 if (operand.IsImmediate() && (operand.immediate() < 0) &&
1363 IsImmAddSub(-operand.immediate())) {
armvixl6e2c8272015-03-31 11:04:14 +01001364 AddSubMacro(rd, rn, -operand.immediate(), S, ADD);
armvixlad96eda2013-06-14 11:42:37 +01001365 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001366 AddSubMacro(rd, rn, operand, S, SUB);
armvixlf37fdc02014-02-05 13:22:16 +00001367 }
1368}
1369
1370
1371void MacroAssembler::Subs(const Register& rd,
1372 const Register& rn,
1373 const Operand& operand) {
armvixl6e2c8272015-03-31 11:04:14 +01001374 Sub(rd, rn, operand, SetFlags);
armvixlad96eda2013-06-14 11:42:37 +01001375}
1376
1377
1378void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001379 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001380 Adds(AppropriateZeroRegFor(rn), rn, operand);
armvixlad96eda2013-06-14 11:42:37 +01001381}
1382
1383
1384void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001385 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001386 Subs(AppropriateZeroRegFor(rn), rn, operand);
armvixlad96eda2013-06-14 11:42:37 +01001387}
1388
1389
armvixl0f35e362016-05-10 13:57:58 +01001390void MacroAssembler::Fcmp(const FPRegister& fn,
1391 double value,
armvixl6e2c8272015-03-31 11:04:14 +01001392 FPTrapFlags trap) {
armvixlb0c8ae22014-03-21 14:03:59 +00001393 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001394 // The worst case for size is:
1395 // * 1 to materialise the constant, using literal pool if necessary
armvixl6e2c8272015-03-31 11:04:14 +01001396 // * 1 instruction for fcmp{e}
armvixlc68cb642014-09-25 18:49:30 +01001397 MacroEmissionCheckScope guard(this);
armvixlb0c8ae22014-03-21 14:03:59 +00001398 if (value != 0.0) {
1399 UseScratchRegisterScope temps(this);
1400 FPRegister tmp = temps.AcquireSameSizeAs(fn);
1401 Fmov(tmp, value);
armvixl6e2c8272015-03-31 11:04:14 +01001402 FPCompareMacro(fn, tmp, trap);
armvixlb0c8ae22014-03-21 14:03:59 +00001403 } else {
armvixl6e2c8272015-03-31 11:04:14 +01001404 FPCompareMacro(fn, value, trap);
armvixlb0c8ae22014-03-21 14:03:59 +00001405 }
1406}
1407
1408
armvixl6e2c8272015-03-31 11:04:14 +01001409void MacroAssembler::Fcmpe(const FPRegister& fn, double value) {
1410 Fcmp(fn, value, EnableTrap);
1411}
1412
1413
armvixl5289c592015-03-02 13:52:04 +00001414void MacroAssembler::Fmov(VRegister vd, double imm) {
armvixlb0c8ae22014-03-21 14:03:59 +00001415 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001416 // Floating point immediates are loaded through the literal pool.
1417 MacroEmissionCheckScope guard(this);
1418
armvixl5289c592015-03-02 13:52:04 +00001419 if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
1420 Fmov(vd, static_cast<float>(imm));
armvixlb0c8ae22014-03-21 14:03:59 +00001421 return;
1422 }
1423
armvixl5289c592015-03-02 13:52:04 +00001424 VIXL_ASSERT(vd.Is1D() || vd.Is2D());
armvixlb0c8ae22014-03-21 14:03:59 +00001425 if (IsImmFP64(imm)) {
armvixl5289c592015-03-02 13:52:04 +00001426 fmov(vd, imm);
armvixlb0c8ae22014-03-21 14:03:59 +00001427 } else {
armvixl5289c592015-03-02 13:52:04 +00001428 uint64_t rawbits = double_to_rawbits(imm);
1429 if (vd.IsScalar()) {
1430 if (rawbits == 0) {
1431 fmov(vd, xzr);
1432 } else {
armvixldb644342015-07-21 11:37:10 +01001433 ldr(vd,
1434 new Literal<double>(imm,
1435 &literal_pool_,
1436 RawLiteral::kDeletedOnPlacementByPool));
armvixl5289c592015-03-02 13:52:04 +00001437 }
1438 } else {
1439 // TODO: consider NEON support for load literal.
1440 Movi(vd, rawbits);
1441 }
armvixlb0c8ae22014-03-21 14:03:59 +00001442 }
1443}
1444
1445
armvixl5289c592015-03-02 13:52:04 +00001446void MacroAssembler::Fmov(VRegister vd, float imm) {
armvixlb0c8ae22014-03-21 14:03:59 +00001447 VIXL_ASSERT(allow_macro_instructions_);
armvixlc68cb642014-09-25 18:49:30 +01001448 // Floating point immediates are loaded through the literal pool.
1449 MacroEmissionCheckScope guard(this);
1450
armvixl5289c592015-03-02 13:52:04 +00001451 if (vd.Is1D() || vd.Is2D()) {
1452 Fmov(vd, static_cast<double>(imm));
armvixlb0c8ae22014-03-21 14:03:59 +00001453 return;
1454 }
1455
armvixl5289c592015-03-02 13:52:04 +00001456 VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
armvixlb0c8ae22014-03-21 14:03:59 +00001457 if (IsImmFP32(imm)) {
armvixl5289c592015-03-02 13:52:04 +00001458 fmov(vd, imm);
armvixlb0c8ae22014-03-21 14:03:59 +00001459 } else {
armvixl5289c592015-03-02 13:52:04 +00001460 uint32_t rawbits = float_to_rawbits(imm);
1461 if (vd.IsScalar()) {
1462 if (rawbits == 0) {
1463 fmov(vd, wzr);
1464 } else {
armvixldb644342015-07-21 11:37:10 +01001465 ldr(vd,
1466 new Literal<float>(imm,
1467 &literal_pool_,
1468 RawLiteral::kDeletedOnPlacementByPool));
armvixl5289c592015-03-02 13:52:04 +00001469 }
1470 } else {
1471 // TODO: consider NEON support for load literal.
1472 Movi(vd, rawbits);
1473 }
armvixlb0c8ae22014-03-21 14:03:59 +00001474 }
1475}
1476
1477
armvixl0f35e362016-05-10 13:57:58 +01001478void MacroAssembler::Neg(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001479 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001480 if (operand.IsImmediate()) {
1481 Mov(rd, -operand.immediate());
1482 } else {
armvixlf37fdc02014-02-05 13:22:16 +00001483 Sub(rd, AppropriateZeroRegFor(rd), operand);
armvixlad96eda2013-06-14 11:42:37 +01001484 }
1485}
1486
1487
armvixl0f35e362016-05-10 13:57:58 +01001488void MacroAssembler::Negs(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001489 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001490 Subs(rd, AppropriateZeroRegFor(rd), operand);
1491}
1492
1493
armvixl4a102ba2014-07-14 09:02:40 +01001494bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
1495 int64_t imm) {
armvixl330dc712014-11-25 10:38:32 +00001496 return OneInstrMoveImmediateHelper(this, dst, imm);
armvixl4a102ba2014-07-14 09:02:40 +01001497}
1498
1499
1500Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
1501 int64_t imm) {
1502 int reg_size = dst.size();
1503
1504 // Encode the immediate in a single move instruction, if possible.
1505 if (TryOneInstrMoveImmediate(dst, imm)) {
1506 // The move was successful; nothing to do here.
1507 } else {
1508 // Pre-shift the immediate to the least-significant bits of the register.
1509 int shift_low = CountTrailingZeros(imm, reg_size);
1510 int64_t imm_low = imm >> shift_low;
1511
1512 // Pre-shift the immediate to the most-significant bits of the register,
1513 // inserting set bits in the least-significant bits.
1514 int shift_high = CountLeadingZeros(imm, reg_size);
armvixl5289c592015-03-02 13:52:04 +00001515 int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
armvixl4a102ba2014-07-14 09:02:40 +01001516
1517 if (TryOneInstrMoveImmediate(dst, imm_low)) {
1518 // The new immediate has been moved into the destination's low bits:
1519 // return a new leftward-shifting operand.
1520 return Operand(dst, LSL, shift_low);
1521 } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
1522 // The new immediate has been moved into the destination's high bits:
1523 // return a new rightward-shifting operand.
1524 return Operand(dst, LSR, shift_high);
1525 } else {
1526 Mov(dst, imm);
1527 }
1528 }
1529 return Operand(dst);
1530}
1531
1532
armvixl5289c592015-03-02 13:52:04 +00001533void MacroAssembler::ComputeAddress(const Register& dst,
1534 const MemOperand& mem_op) {
1535 // We cannot handle pre-indexing or post-indexing.
1536 VIXL_ASSERT(mem_op.addrmode() == Offset);
1537 Register base = mem_op.base();
1538 if (mem_op.IsImmediateOffset()) {
1539 Add(dst, base, mem_op.offset());
1540 } else {
1541 VIXL_ASSERT(mem_op.IsRegisterOffset());
1542 Register reg_offset = mem_op.regoffset();
1543 Shift shift = mem_op.shift();
1544 Extend extend = mem_op.extend();
1545 if (shift == NO_SHIFT) {
1546 VIXL_ASSERT(extend != NO_EXTEND);
1547 Add(dst, base, Operand(reg_offset, extend, mem_op.shift_amount()));
1548 } else {
1549 VIXL_ASSERT(extend == NO_EXTEND);
1550 Add(dst, base, Operand(reg_offset, shift, mem_op.shift_amount()));
1551 }
1552 }
1553}
1554
1555
armvixlad96eda2013-06-14 11:42:37 +01001556void MacroAssembler::AddSubMacro(const Register& rd,
1557 const Register& rn,
1558 const Operand& operand,
1559 FlagsUpdate S,
1560 AddSubOp op) {
armvixlc68cb642014-09-25 18:49:30 +01001561 // Worst case is add/sub immediate:
1562 // * up to 4 instructions to materialise the constant
1563 // * 1 instruction for add/sub
1564 MacroEmissionCheckScope guard(this);
1565
armvixlf37fdc02014-02-05 13:22:16 +00001566 if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1567 (S == LeaveFlags)) {
1568 // The instruction would be a nop. Avoid generating useless code.
1569 return;
1570 }
1571
armvixlad96eda2013-06-14 11:42:37 +01001572 if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
armvixl0f35e362016-05-10 13:57:58 +01001573 (rn.IsZero() && !operand.IsShiftedRegister()) ||
armvixlad96eda2013-06-14 11:42:37 +01001574 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
armvixlb0c8ae22014-03-21 14:03:59 +00001575 UseScratchRegisterScope temps(this);
1576 Register temp = temps.AcquireSameSizeAs(rn);
armvixl4a102ba2014-07-14 09:02:40 +01001577 if (operand.IsImmediate()) {
1578 Operand imm_operand =
1579 MoveImmediateForShiftedOp(temp, operand.immediate());
1580 AddSub(rd, rn, imm_operand, S, op);
1581 } else {
1582 Mov(temp, operand);
1583 AddSub(rd, rn, temp, S, op);
1584 }
armvixlad96eda2013-06-14 11:42:37 +01001585 } else {
1586 AddSub(rd, rn, operand, S, op);
1587 }
1588}
1589
1590
1591void MacroAssembler::Adc(const Register& rd,
1592 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +00001593 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001594 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001595 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1596}
1597
1598
1599void MacroAssembler::Adcs(const Register& rd,
1600 const Register& rn,
1601 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001602 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001603 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
armvixlad96eda2013-06-14 11:42:37 +01001604}
1605
1606
1607void MacroAssembler::Sbc(const Register& rd,
1608 const Register& rn,
armvixlf37fdc02014-02-05 13:22:16 +00001609 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001610 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001611 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1612}
1613
1614
1615void MacroAssembler::Sbcs(const Register& rd,
1616 const Register& rn,
1617 const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001618 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001619 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
armvixlad96eda2013-06-14 11:42:37 +01001620}
1621
1622
armvixl0f35e362016-05-10 13:57:58 +01001623void MacroAssembler::Ngc(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001624 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001625 Register zr = AppropriateZeroRegFor(rd);
armvixlf37fdc02014-02-05 13:22:16 +00001626 Sbc(rd, zr, operand);
1627}
1628
1629
armvixl0f35e362016-05-10 13:57:58 +01001630void MacroAssembler::Ngcs(const Register& rd, const Operand& operand) {
armvixlb0c8ae22014-03-21 14:03:59 +00001631 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00001632 Register zr = AppropriateZeroRegFor(rd);
1633 Sbcs(rd, zr, operand);
armvixlad96eda2013-06-14 11:42:37 +01001634}
1635
1636
1637void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1638 const Register& rn,
1639 const Operand& operand,
1640 FlagsUpdate S,
1641 AddSubWithCarryOp op) {
armvixlb0c8ae22014-03-21 14:03:59 +00001642 VIXL_ASSERT(rd.size() == rn.size());
armvixlc68cb642014-09-25 18:49:30 +01001643 // Worst case is addc/subc immediate:
1644 // * up to 4 instructions to materialise the constant
1645 // * 1 instruction for add/sub
1646 MacroEmissionCheckScope guard(this);
armvixlb0c8ae22014-03-21 14:03:59 +00001647 UseScratchRegisterScope temps(this);
armvixlad96eda2013-06-14 11:42:37 +01001648
1649 if (operand.IsImmediate() ||
1650 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
1651 // Add/sub with carry (immediate or ROR shifted register.)
armvixlb0c8ae22014-03-21 14:03:59 +00001652 Register temp = temps.AcquireSameSizeAs(rn);
armvixlad96eda2013-06-14 11:42:37 +01001653 Mov(temp, operand);
1654 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1655 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
1656 // Add/sub with carry (shifted register).
armvixlb0c8ae22014-03-21 14:03:59 +00001657 VIXL_ASSERT(operand.reg().size() == rd.size());
1658 VIXL_ASSERT(operand.shift() != ROR);
1659 VIXL_ASSERT(is_uintn(rd.size() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
armvixl0f35e362016-05-10 13:57:58 +01001660 operand.shift_amount()));
armvixlb0c8ae22014-03-21 14:03:59 +00001661 temps.Exclude(operand.reg());
1662 Register temp = temps.AcquireSameSizeAs(rn);
armvixlad96eda2013-06-14 11:42:37 +01001663 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
1664 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1665 } else if (operand.IsExtendedRegister()) {
1666 // Add/sub with carry (extended register).
armvixlb0c8ae22014-03-21 14:03:59 +00001667 VIXL_ASSERT(operand.reg().size() <= rd.size());
armvixlad96eda2013-06-14 11:42:37 +01001668 // Add/sub extended supports a shift <= 4. We want to support exactly the
1669 // same modes.
armvixlb0c8ae22014-03-21 14:03:59 +00001670 VIXL_ASSERT(operand.shift_amount() <= 4);
1671 VIXL_ASSERT(operand.reg().Is64Bits() ||
armvixl0f35e362016-05-10 13:57:58 +01001672 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
armvixlb0c8ae22014-03-21 14:03:59 +00001673 temps.Exclude(operand.reg());
1674 Register temp = temps.AcquireSameSizeAs(rn);
armvixl0f35e362016-05-10 13:57:58 +01001675 EmitExtendShift(temp,
1676 operand.reg(),
1677 operand.extend(),
armvixlad96eda2013-06-14 11:42:37 +01001678 operand.shift_amount());
1679 AddSubWithCarry(rd, rn, Operand(temp), S, op);
1680 } else {
1681 // The addressing mode is directly supported by the instruction.
1682 AddSubWithCarry(rd, rn, operand, S, op);
1683 }
1684}
1685
1686
armvixl0f35e362016-05-10 13:57:58 +01001687#define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
1688 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
1689 VIXL_ASSERT(allow_macro_instructions_); \
1690 LoadStoreMacro(REG, addr, OP); \
1691 }
armvixlad96eda2013-06-14 11:42:37 +01001692LS_MACRO_LIST(DEFINE_FUNCTION)
1693#undef DEFINE_FUNCTION
1694
armvixl330dc712014-11-25 10:38:32 +00001695
armvixlad96eda2013-06-14 11:42:37 +01001696void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
1697 const MemOperand& addr,
1698 LoadStoreOp op) {
armvixlc68cb642014-09-25 18:49:30 +01001699 // Worst case is ldr/str pre/post index:
1700 // * 1 instruction for ldr/str
1701 // * up to 4 instructions to materialise the constant
1702 // * 1 instruction to update the base
1703 MacroEmissionCheckScope guard(this);
1704
armvixlad96eda2013-06-14 11:42:37 +01001705 int64_t offset = addr.offset();
armvixl5289c592015-03-02 13:52:04 +00001706 unsigned access_size = CalcLSDataSize(op);
armvixlad96eda2013-06-14 11:42:37 +01001707
1708 // Check if an immediate offset fits in the immediate field of the
1709 // appropriate instruction. If not, emit two instructions to perform
1710 // the operation.
armvixl5289c592015-03-02 13:52:04 +00001711 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
armvixlad96eda2013-06-14 11:42:37 +01001712 !IsImmLSUnscaled(offset)) {
1713 // Immediate offset that can't be encoded using unsigned or unscaled
1714 // addressing modes.
armvixlb0c8ae22014-03-21 14:03:59 +00001715 UseScratchRegisterScope temps(this);
1716 Register temp = temps.AcquireSameSizeAs(addr.base());
armvixlad96eda2013-06-14 11:42:37 +01001717 Mov(temp, addr.offset());
1718 LoadStore(rt, MemOperand(addr.base(), temp), op);
1719 } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
1720 // Post-index beyond unscaled addressing range.
1721 LoadStore(rt, MemOperand(addr.base()), op);
1722 Add(addr.base(), addr.base(), Operand(offset));
1723 } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
1724 // Pre-index beyond unscaled addressing range.
1725 Add(addr.base(), addr.base(), Operand(offset));
1726 LoadStore(rt, MemOperand(addr.base()), op);
1727 } else {
1728 // Encodable in one load/store instruction.
1729 LoadStore(rt, addr, op);
1730 }
1731}
1732
1733
armvixl0f35e362016-05-10 13:57:58 +01001734#define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
1735 void MacroAssembler::FN(const REGTYPE REG, \
1736 const REGTYPE REG2, \
1737 const MemOperand& addr) { \
1738 VIXL_ASSERT(allow_macro_instructions_); \
1739 LoadStorePairMacro(REG, REG2, addr, OP); \
1740 }
armvixlc68cb642014-09-25 18:49:30 +01001741LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
1742#undef DEFINE_FUNCTION
1743
1744void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
1745 const CPURegister& rt2,
1746 const MemOperand& addr,
1747 LoadStorePairOp op) {
1748 // TODO(all): Should we support register offset for load-store-pair?
1749 VIXL_ASSERT(!addr.IsRegisterOffset());
1750 // Worst case is ldp/stp immediate:
1751 // * 1 instruction for ldp/stp
1752 // * up to 4 instructions to materialise the constant
1753 // * 1 instruction to update the base
1754 MacroEmissionCheckScope guard(this);
1755
1756 int64_t offset = addr.offset();
armvixl5289c592015-03-02 13:52:04 +00001757 unsigned access_size = CalcLSPairDataSize(op);
armvixlc68cb642014-09-25 18:49:30 +01001758
1759 // Check if the offset fits in the immediate field of the appropriate
1760 // instruction. If not, emit two instructions to perform the operation.
armvixl5289c592015-03-02 13:52:04 +00001761 if (IsImmLSPair(offset, access_size)) {
armvixlc68cb642014-09-25 18:49:30 +01001762 // Encodable in one load/store pair instruction.
1763 LoadStorePair(rt, rt2, addr, op);
1764 } else {
1765 Register base = addr.base();
1766 if (addr.IsImmediateOffset()) {
1767 UseScratchRegisterScope temps(this);
1768 Register temp = temps.AcquireSameSizeAs(base);
1769 Add(temp, base, offset);
1770 LoadStorePair(rt, rt2, MemOperand(temp), op);
1771 } else if (addr.IsPostIndex()) {
1772 LoadStorePair(rt, rt2, MemOperand(base), op);
1773 Add(base, base, offset);
1774 } else {
1775 VIXL_ASSERT(addr.IsPreIndex());
1776 Add(base, base, offset);
1777 LoadStorePair(rt, rt2, MemOperand(base), op);
1778 }
1779 }
1780}
1781
armvixl330dc712014-11-25 10:38:32 +00001782
1783void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
1784 MacroEmissionCheckScope guard(this);
1785
1786 // There are no pre- or post-index modes for prfm.
1787 VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
1788
1789 // The access size is implicitly 8 bytes for all prefetch operations.
armvixl5289c592015-03-02 13:52:04 +00001790 unsigned size = kXRegSizeInBytesLog2;
armvixl330dc712014-11-25 10:38:32 +00001791
1792 // Check if an immediate offset fits in the immediate field of the
1793 // appropriate instruction. If not, emit two instructions to perform
1794 // the operation.
1795 if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.offset(), size) &&
1796 !IsImmLSUnscaled(addr.offset())) {
1797 // Immediate offset that can't be encoded using unsigned or unscaled
1798 // addressing modes.
1799 UseScratchRegisterScope temps(this);
1800 Register temp = temps.AcquireSameSizeAs(addr.base());
1801 Mov(temp, addr.offset());
1802 Prefetch(op, MemOperand(addr.base(), temp));
1803 } else {
1804 // Simple register-offsets are encodable in one instruction.
1805 Prefetch(op, addr);
1806 }
1807}
1808
1809
armvixl0f35e362016-05-10 13:57:58 +01001810void MacroAssembler::Push(const CPURegister& src0,
1811 const CPURegister& src1,
1812 const CPURegister& src2,
1813 const CPURegister& src3) {
armvixlb0c8ae22014-03-21 14:03:59 +00001814 VIXL_ASSERT(allow_macro_instructions_);
1815 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1816 VIXL_ASSERT(src0.IsValid());
armvixlad96eda2013-06-14 11:42:37 +01001817
1818 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
1819 int size = src0.SizeInBytes();
1820
1821 PrepareForPush(count, size);
1822 PushHelper(count, size, src0, src1, src2, src3);
1823}
1824
1825
armvixl0f35e362016-05-10 13:57:58 +01001826void MacroAssembler::Pop(const CPURegister& dst0,
1827 const CPURegister& dst1,
1828 const CPURegister& dst2,
1829 const CPURegister& dst3) {
armvixlad96eda2013-06-14 11:42:37 +01001830 // It is not valid to pop into the same register more than once in one
1831 // instruction, not even into the zero register.
armvixlb0c8ae22014-03-21 14:03:59 +00001832 VIXL_ASSERT(allow_macro_instructions_);
1833 VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
1834 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1835 VIXL_ASSERT(dst0.IsValid());
armvixlad96eda2013-06-14 11:42:37 +01001836
1837 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
1838 int size = dst0.SizeInBytes();
1839
1840 PrepareForPop(count, size);
1841 PopHelper(count, size, dst0, dst1, dst2, dst3);
1842}
1843
1844
1845void MacroAssembler::PushCPURegList(CPURegList registers) {
armvixl6e2c8272015-03-31 11:04:14 +01001846 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1847 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
armvixlb0c8ae22014-03-21 14:03:59 +00001848 VIXL_ASSERT(allow_macro_instructions_);
armvixl6e2c8272015-03-31 11:04:14 +01001849
1850 int reg_size = registers.RegisterSizeInBytes();
1851 PrepareForPush(registers.Count(), reg_size);
1852
1853 // Bump the stack pointer and store two registers at the bottom.
1854 int size = registers.TotalSizeInBytes();
1855 const CPURegister& bottom_0 = registers.PopLowestIndex();
1856 const CPURegister& bottom_1 = registers.PopLowestIndex();
1857 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1858 Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
1859 } else if (bottom_0.IsValid()) {
1860 Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
1861 }
1862
1863 int offset = 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001864 while (!registers.IsEmpty()) {
armvixl6e2c8272015-03-31 11:04:14 +01001865 const CPURegister& src0 = registers.PopLowestIndex();
1866 const CPURegister& src1 = registers.PopLowestIndex();
1867 if (src1.IsValid()) {
1868 Stp(src0, src1, MemOperand(StackPointer(), offset));
1869 } else {
1870 Str(src0, MemOperand(StackPointer(), offset));
1871 }
1872 offset += 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001873 }
1874}
1875
1876
1877void MacroAssembler::PopCPURegList(CPURegList registers) {
armvixl6e2c8272015-03-31 11:04:14 +01001878 VIXL_ASSERT(!registers.Overlaps(*TmpList()));
1879 VIXL_ASSERT(!registers.Overlaps(*FPTmpList()));
armvixlb0c8ae22014-03-21 14:03:59 +00001880 VIXL_ASSERT(allow_macro_instructions_);
armvixl6e2c8272015-03-31 11:04:14 +01001881
1882 int reg_size = registers.RegisterSizeInBytes();
1883 PrepareForPop(registers.Count(), reg_size);
1884
1885
1886 int size = registers.TotalSizeInBytes();
1887 const CPURegister& bottom_0 = registers.PopLowestIndex();
1888 const CPURegister& bottom_1 = registers.PopLowestIndex();
1889
1890 int offset = 2 * reg_size;
armvixlad96eda2013-06-14 11:42:37 +01001891 while (!registers.IsEmpty()) {
armvixlad96eda2013-06-14 11:42:37 +01001892 const CPURegister& dst0 = registers.PopLowestIndex();
1893 const CPURegister& dst1 = registers.PopLowestIndex();
armvixl6e2c8272015-03-31 11:04:14 +01001894 if (dst1.IsValid()) {
1895 Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
1896 } else {
1897 Ldr(dst0, MemOperand(StackPointer(), offset));
1898 }
1899 offset += 2 * reg_size;
1900 }
1901
1902 // Load the two registers at the bottom and drop the stack pointer.
1903 if (bottom_0.IsValid() && bottom_1.IsValid()) {
1904 Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
1905 } else if (bottom_0.IsValid()) {
1906 Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
armvixlad96eda2013-06-14 11:42:37 +01001907 }
1908}
1909
1910
1911void MacroAssembler::PushMultipleTimes(int count, Register src) {
armvixlb0c8ae22014-03-21 14:03:59 +00001912 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01001913 int size = src.SizeInBytes();
1914
1915 PrepareForPush(count, size);
1916 // Push up to four registers at a time if possible because if the current
1917 // stack pointer is sp and the register size is 32, registers must be pushed
1918 // in blocks of four in order to maintain the 16-byte alignment for sp.
1919 while (count >= 4) {
1920 PushHelper(4, size, src, src, src, src);
1921 count -= 4;
1922 }
1923 if (count >= 2) {
1924 PushHelper(2, size, src, src, NoReg, NoReg);
1925 count -= 2;
1926 }
1927 if (count == 1) {
1928 PushHelper(1, size, src, NoReg, NoReg, NoReg);
1929 count -= 1;
1930 }
armvixlb0c8ae22014-03-21 14:03:59 +00001931 VIXL_ASSERT(count == 0);
armvixlad96eda2013-06-14 11:42:37 +01001932}
1933
1934
armvixl0f35e362016-05-10 13:57:58 +01001935void MacroAssembler::PushHelper(int count,
1936 int size,
armvixlad96eda2013-06-14 11:42:37 +01001937 const CPURegister& src0,
1938 const CPURegister& src1,
1939 const CPURegister& src2,
1940 const CPURegister& src3) {
1941 // Ensure that we don't unintentionally modify scratch or debug registers.
armvixlc68cb642014-09-25 18:49:30 +01001942 // Worst case for size is 2 stp.
armvixl0f35e362016-05-10 13:57:58 +01001943 InstructionAccurateScope scope(this,
1944 2,
armvixlc68cb642014-09-25 18:49:30 +01001945 InstructionAccurateScope::kMaximumSize);
armvixlad96eda2013-06-14 11:42:37 +01001946
armvixlb0c8ae22014-03-21 14:03:59 +00001947 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1948 VIXL_ASSERT(size == src0.SizeInBytes());
armvixlad96eda2013-06-14 11:42:37 +01001949
1950 // When pushing multiple registers, the store order is chosen such that
1951 // Push(a, b) is equivalent to Push(a) followed by Push(b).
1952 switch (count) {
1953 case 1:
armvixlb0c8ae22014-03-21 14:03:59 +00001954 VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001955 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
1956 break;
1957 case 2:
armvixlb0c8ae22014-03-21 14:03:59 +00001958 VIXL_ASSERT(src2.IsNone() && src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001959 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
1960 break;
1961 case 3:
armvixlb0c8ae22014-03-21 14:03:59 +00001962 VIXL_ASSERT(src3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001963 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
1964 str(src0, MemOperand(StackPointer(), 2 * size));
1965 break;
1966 case 4:
1967 // Skip over 4 * size, then fill in the gap. This allows four W registers
1968 // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
1969 // all times.
1970 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
1971 stp(src1, src0, MemOperand(StackPointer(), 2 * size));
1972 break;
1973 default:
armvixlb0c8ae22014-03-21 14:03:59 +00001974 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +01001975 }
1976}
1977
1978
armvixl0f35e362016-05-10 13:57:58 +01001979void MacroAssembler::PopHelper(int count,
1980 int size,
armvixlad96eda2013-06-14 11:42:37 +01001981 const CPURegister& dst0,
1982 const CPURegister& dst1,
1983 const CPURegister& dst2,
1984 const CPURegister& dst3) {
1985 // Ensure that we don't unintentionally modify scratch or debug registers.
armvixlc68cb642014-09-25 18:49:30 +01001986 // Worst case for size is 2 ldp.
armvixl0f35e362016-05-10 13:57:58 +01001987 InstructionAccurateScope scope(this,
1988 2,
armvixlc68cb642014-09-25 18:49:30 +01001989 InstructionAccurateScope::kMaximumSize);
armvixlad96eda2013-06-14 11:42:37 +01001990
armvixlb0c8ae22014-03-21 14:03:59 +00001991 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1992 VIXL_ASSERT(size == dst0.SizeInBytes());
armvixlad96eda2013-06-14 11:42:37 +01001993
1994 // When popping multiple registers, the load order is chosen such that
1995 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
1996 switch (count) {
1997 case 1:
armvixlb0c8ae22014-03-21 14:03:59 +00001998 VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01001999 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
2000 break;
2001 case 2:
armvixlb0c8ae22014-03-21 14:03:59 +00002002 VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002003 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
2004 break;
2005 case 3:
armvixlb0c8ae22014-03-21 14:03:59 +00002006 VIXL_ASSERT(dst3.IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002007 ldr(dst2, MemOperand(StackPointer(), 2 * size));
2008 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
2009 break;
2010 case 4:
2011 // Load the higher addresses first, then load the lower addresses and skip
2012 // the whole block in the second instruction. This allows four W registers
2013 // to be popped using sp, whilst maintaining 16-byte alignment for sp at
2014 // all times.
2015 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
2016 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
2017 break;
2018 default:
armvixlb0c8ae22014-03-21 14:03:59 +00002019 VIXL_UNREACHABLE();
armvixlad96eda2013-06-14 11:42:37 +01002020 }
2021}
2022
2023
2024void MacroAssembler::PrepareForPush(int count, int size) {
2025 if (sp.Is(StackPointer())) {
2026 // If the current stack pointer is sp, then it must be aligned to 16 bytes
2027 // on entry and the total size of the specified registers must also be a
2028 // multiple of 16 bytes.
armvixlb0c8ae22014-03-21 14:03:59 +00002029 VIXL_ASSERT((count * size) % 16 == 0);
armvixlad96eda2013-06-14 11:42:37 +01002030 } else {
2031 // Even if the current stack pointer is not the system stack pointer (sp),
2032 // the system stack pointer will still be modified in order to comply with
2033 // ABI rules about accessing memory below the system stack pointer.
2034 BumpSystemStackPointer(count * size);
2035 }
2036}
2037
2038
2039void MacroAssembler::PrepareForPop(int count, int size) {
armvixldb644342015-07-21 11:37:10 +01002040 USE(count, size);
armvixlad96eda2013-06-14 11:42:37 +01002041 if (sp.Is(StackPointer())) {
2042 // If the current stack pointer is sp, then it must be aligned to 16 bytes
2043 // on entry and the total size of the specified registers must also be a
2044 // multiple of 16 bytes.
armvixlb0c8ae22014-03-21 14:03:59 +00002045 VIXL_ASSERT((count * size) % 16 == 0);
armvixlad96eda2013-06-14 11:42:37 +01002046 }
2047}
2048
2049void MacroAssembler::Poke(const Register& src, const Operand& offset) {
armvixlb0c8ae22014-03-21 14:03:59 +00002050 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002051 if (offset.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002052 VIXL_ASSERT(offset.immediate() >= 0);
armvixlad96eda2013-06-14 11:42:37 +01002053 }
2054
2055 Str(src, MemOperand(StackPointer(), offset));
2056}
2057
2058
2059void MacroAssembler::Peek(const Register& dst, const Operand& offset) {
armvixlb0c8ae22014-03-21 14:03:59 +00002060 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002061 if (offset.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002062 VIXL_ASSERT(offset.immediate() >= 0);
armvixlad96eda2013-06-14 11:42:37 +01002063 }
2064
2065 Ldr(dst, MemOperand(StackPointer(), offset));
2066}
2067
2068
2069void MacroAssembler::Claim(const Operand& size) {
armvixlb0c8ae22014-03-21 14:03:59 +00002070 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00002071
2072 if (size.IsZero()) {
2073 return;
2074 }
2075
armvixlad96eda2013-06-14 11:42:37 +01002076 if (size.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002077 VIXL_ASSERT(size.immediate() > 0);
armvixlad96eda2013-06-14 11:42:37 +01002078 if (sp.Is(StackPointer())) {
armvixlb0c8ae22014-03-21 14:03:59 +00002079 VIXL_ASSERT((size.immediate() % 16) == 0);
armvixlad96eda2013-06-14 11:42:37 +01002080 }
2081 }
2082
2083 if (!sp.Is(StackPointer())) {
2084 BumpSystemStackPointer(size);
2085 }
2086
2087 Sub(StackPointer(), StackPointer(), size);
2088}
2089
2090
2091void MacroAssembler::Drop(const Operand& size) {
armvixlb0c8ae22014-03-21 14:03:59 +00002092 VIXL_ASSERT(allow_macro_instructions_);
armvixlf37fdc02014-02-05 13:22:16 +00002093
2094 if (size.IsZero()) {
2095 return;
2096 }
2097
armvixlad96eda2013-06-14 11:42:37 +01002098 if (size.IsImmediate()) {
armvixlb0c8ae22014-03-21 14:03:59 +00002099 VIXL_ASSERT(size.immediate() > 0);
armvixlad96eda2013-06-14 11:42:37 +01002100 if (sp.Is(StackPointer())) {
armvixlb0c8ae22014-03-21 14:03:59 +00002101 VIXL_ASSERT((size.immediate() % 16) == 0);
armvixlad96eda2013-06-14 11:42:37 +01002102 }
2103 }
2104
2105 Add(StackPointer(), StackPointer(), size);
2106}
2107
2108
2109void MacroAssembler::PushCalleeSavedRegisters() {
2110 // Ensure that the macro-assembler doesn't use any scratch registers.
armvixlc68cb642014-09-25 18:49:30 +01002111 // 10 stp will be emitted.
2112 // TODO(all): Should we use GetCalleeSaved and SavedFP.
2113 InstructionAccurateScope scope(this, 10);
armvixlad96eda2013-06-14 11:42:37 +01002114
2115 // This method must not be called unless the current stack pointer is sp.
armvixlb0c8ae22014-03-21 14:03:59 +00002116 VIXL_ASSERT(sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002117
armvixldb644342015-07-21 11:37:10 +01002118 MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);
armvixlad96eda2013-06-14 11:42:37 +01002119
armvixlad96eda2013-06-14 11:42:37 +01002120 stp(x29, x30, tos);
2121 stp(x27, x28, tos);
2122 stp(x25, x26, tos);
2123 stp(x23, x24, tos);
2124 stp(x21, x22, tos);
2125 stp(x19, x20, tos);
armvixl5799d6c2014-05-01 11:05:00 +01002126
2127 stp(d14, d15, tos);
2128 stp(d12, d13, tos);
2129 stp(d10, d11, tos);
2130 stp(d8, d9, tos);
armvixlad96eda2013-06-14 11:42:37 +01002131}
2132
2133
2134void MacroAssembler::PopCalleeSavedRegisters() {
2135 // Ensure that the macro-assembler doesn't use any scratch registers.
armvixlc68cb642014-09-25 18:49:30 +01002136 // 10 ldp will be emitted.
2137 // TODO(all): Should we use GetCalleeSaved and SavedFP.
2138 InstructionAccurateScope scope(this, 10);
armvixlad96eda2013-06-14 11:42:37 +01002139
2140 // This method must not be called unless the current stack pointer is sp.
armvixlb0c8ae22014-03-21 14:03:59 +00002141 VIXL_ASSERT(sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002142
2143 MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
2144
armvixl5799d6c2014-05-01 11:05:00 +01002145 ldp(d8, d9, tos);
2146 ldp(d10, d11, tos);
2147 ldp(d12, d13, tos);
2148 ldp(d14, d15, tos);
2149
armvixlad96eda2013-06-14 11:42:37 +01002150 ldp(x19, x20, tos);
2151 ldp(x21, x22, tos);
2152 ldp(x23, x24, tos);
2153 ldp(x25, x26, tos);
2154 ldp(x27, x28, tos);
2155 ldp(x29, x30, tos);
armvixlad96eda2013-06-14 11:42:37 +01002156}
2157
armvixl6e2c8272015-03-31 11:04:14 +01002158void MacroAssembler::LoadCPURegList(CPURegList registers,
2159 const MemOperand& src) {
2160 LoadStoreCPURegListHelper(kLoad, registers, src);
2161}
2162
2163void MacroAssembler::StoreCPURegList(CPURegList registers,
2164 const MemOperand& dst) {
2165 LoadStoreCPURegListHelper(kStore, registers, dst);
2166}
2167
2168
2169void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
2170 CPURegList registers,
2171 const MemOperand& mem) {
2172 // We do not handle pre-indexing or post-indexing.
2173 VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
2174 VIXL_ASSERT(!registers.Overlaps(tmp_list_));
2175 VIXL_ASSERT(!registers.Overlaps(fptmp_list_));
2176 VIXL_ASSERT(!registers.IncludesAliasOf(sp));
2177
2178 UseScratchRegisterScope temps(this);
2179
armvixl0f35e362016-05-10 13:57:58 +01002180 MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers, mem, &temps);
armvixl6e2c8272015-03-31 11:04:14 +01002181
2182 while (registers.Count() >= 2) {
2183 const CPURegister& dst0 = registers.PopLowestIndex();
2184 const CPURegister& dst1 = registers.PopLowestIndex();
2185 if (op == kStore) {
2186 Stp(dst0, dst1, loc);
2187 } else {
2188 VIXL_ASSERT(op == kLoad);
2189 Ldp(dst0, dst1, loc);
2190 }
2191 loc.AddOffset(2 * registers.RegisterSizeInBytes());
2192 }
2193 if (!registers.IsEmpty()) {
2194 if (op == kStore) {
2195 Str(registers.PopLowestIndex(), loc);
2196 } else {
2197 VIXL_ASSERT(op == kLoad);
2198 Ldr(registers.PopLowestIndex(), loc);
2199 }
2200 }
2201}
2202
2203MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
2204 const CPURegList& registers,
2205 const MemOperand& mem,
2206 UseScratchRegisterScope* scratch_scope) {
2207 // If necessary, pre-compute the base address for the accesses.
2208 if (mem.IsRegisterOffset()) {
2209 Register reg_base = scratch_scope->AcquireX();
2210 ComputeAddress(reg_base, mem);
2211 return MemOperand(reg_base);
2212
2213 } else if (mem.IsImmediateOffset()) {
2214 int reg_size = registers.RegisterSizeInBytes();
2215 int total_size = registers.TotalSizeInBytes();
2216 int64_t min_offset = mem.offset();
2217 int64_t max_offset = mem.offset() + std::max(0, total_size - 2 * reg_size);
2218 if ((registers.Count() >= 2) &&
2219 (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
2220 !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
2221 Register reg_base = scratch_scope->AcquireX();
2222 ComputeAddress(reg_base, mem);
2223 return MemOperand(reg_base);
2224 }
2225 }
2226
2227 return mem;
2228}
2229
armvixlad96eda2013-06-14 11:42:37 +01002230void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
armvixlb0c8ae22014-03-21 14:03:59 +00002231 VIXL_ASSERT(!sp.Is(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002232 // TODO: Several callers rely on this not using scratch registers, so we use
2233 // the assembler directly here. However, this means that large immediate
2234 // values of 'space' cannot be handled.
armvixlc68cb642014-09-25 18:49:30 +01002235 InstructionAccurateScope scope(this, 1);
armvixlad96eda2013-06-14 11:42:37 +01002236 sub(sp, StackPointer(), space);
2237}
2238
2239
armvixl5289c592015-03-02 13:52:04 +00002240// TODO(all): Fix printf for NEON registers, and resolve whether we should be
2241// using FPRegister or VRegister here.
2242
armvixlad96eda2013-06-14 11:42:37 +01002243// This is the main Printf implementation. All callee-saved registers are
2244// preserved, but NZCV and the caller-saved registers may be clobbered.
armvixl0f35e362016-05-10 13:57:58 +01002245void MacroAssembler::PrintfNoPreserve(const char* format,
armvixlad96eda2013-06-14 11:42:37 +01002246 const CPURegister& arg0,
2247 const CPURegister& arg1,
2248 const CPURegister& arg2,
2249 const CPURegister& arg3) {
2250 // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2251 // in most cases anyway, so this restriction shouldn't be too serious.
armvixlb0c8ae22014-03-21 14:03:59 +00002252 VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
armvixlad96eda2013-06-14 11:42:37 +01002253
armvixl5799d6c2014-05-01 11:05:00 +01002254 // The provided arguments, and their proper PCS registers.
2255 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
2256 CPURegister pcs[kPrintfMaxArgCount];
2257
2258 int arg_count = kPrintfMaxArgCount;
2259
2260 // The PCS varargs registers for printf. Note that x0 is used for the printf
2261 // format string.
2262 static const CPURegList kPCSVarargs =
2263 CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
2264 static const CPURegList kPCSVarargsFP =
armvixl5289c592015-03-02 13:52:04 +00002265 CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
armvixl5799d6c2014-05-01 11:05:00 +01002266
2267 // We can use caller-saved registers as scratch values, except for the
2268 // arguments and the PCS registers where they might need to go.
armvixlb0c8ae22014-03-21 14:03:59 +00002269 UseScratchRegisterScope temps(this);
armvixl5799d6c2014-05-01 11:05:00 +01002270 temps.Include(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002271 temps.Include(kCallerSavedV);
armvixl5799d6c2014-05-01 11:05:00 +01002272 temps.Exclude(kPCSVarargs);
2273 temps.Exclude(kPCSVarargsFP);
armvixlb0c8ae22014-03-21 14:03:59 +00002274 temps.Exclude(arg0, arg1, arg2, arg3);
2275
armvixl5799d6c2014-05-01 11:05:00 +01002276 // Copies of the arg lists that we can iterate through.
2277 CPURegList pcs_varargs = kPCSVarargs;
2278 CPURegList pcs_varargs_fp = kPCSVarargsFP;
armvixlad96eda2013-06-14 11:42:37 +01002279
armvixl5799d6c2014-05-01 11:05:00 +01002280 // Place the arguments. There are lots of clever tricks and optimizations we
2281 // could use here, but Printf is a debug tool so instead we just try to keep
2282 // it simple: Move each input that isn't already in the right place to a
2283 // scratch register, then move everything back.
2284 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
2285 // Work out the proper PCS register for this argument.
armvixlad96eda2013-06-14 11:42:37 +01002286 if (args[i].IsRegister()) {
armvixl5799d6c2014-05-01 11:05:00 +01002287 pcs[i] = pcs_varargs.PopLowestIndex().X();
2288 // We might only need a W register here. We need to know the size of the
2289 // argument so we can properly encode it for the simulator call.
2290 if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
armvixl5289c592015-03-02 13:52:04 +00002291 } else if (args[i].IsVRegister()) {
armvixl5799d6c2014-05-01 11:05:00 +01002292 // In C, floats are always cast to doubles for varargs calls.
2293 pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
armvixlad96eda2013-06-14 11:42:37 +01002294 } else {
armvixl5799d6c2014-05-01 11:05:00 +01002295 VIXL_ASSERT(args[i].IsNone());
armvixlad96eda2013-06-14 11:42:37 +01002296 arg_count = i;
2297 break;
2298 }
armvixlad96eda2013-06-14 11:42:37 +01002299
armvixl5799d6c2014-05-01 11:05:00 +01002300 // If the argument is already in the right place, leave it where it is.
2301 if (args[i].Aliases(pcs[i])) continue;
armvixlad96eda2013-06-14 11:42:37 +01002302
armvixl5799d6c2014-05-01 11:05:00 +01002303 // Otherwise, if the argument is in a PCS argument register, allocate an
2304 // appropriate scratch register and then move it out of the way.
2305 if (kPCSVarargs.IncludesAliasOf(args[i]) ||
2306 kPCSVarargsFP.IncludesAliasOf(args[i])) {
2307 if (args[i].IsRegister()) {
2308 Register old_arg = Register(args[i]);
2309 Register new_arg = temps.AcquireSameSizeAs(old_arg);
2310 Mov(new_arg, old_arg);
2311 args[i] = new_arg;
2312 } else {
2313 FPRegister old_arg = FPRegister(args[i]);
2314 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
2315 Fmov(new_arg, old_arg);
2316 args[i] = new_arg;
2317 }
armvixlad96eda2013-06-14 11:42:37 +01002318 }
2319 }
2320
armvixl5799d6c2014-05-01 11:05:00 +01002321 // Do a second pass to move values into their final positions and perform any
2322 // conversions that may be required.
2323 for (int i = 0; i < arg_count; i++) {
2324 VIXL_ASSERT(pcs[i].type() == args[i].type());
2325 if (pcs[i].IsRegister()) {
2326 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2327 } else {
armvixl5289c592015-03-02 13:52:04 +00002328 VIXL_ASSERT(pcs[i].IsVRegister());
armvixl5799d6c2014-05-01 11:05:00 +01002329 if (pcs[i].size() == args[i].size()) {
2330 Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
2331 } else {
2332 Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
2333 }
2334 }
armvixlad96eda2013-06-14 11:42:37 +01002335 }
2336
2337 // Load the format string into x0, as per the procedure-call standard.
2338 //
2339 // To make the code as portable as possible, the format string is encoded
2340 // directly in the instruction stream. It might be cleaner to encode it in a
2341 // literal pool, but since Printf is usually used for debugging, it is
2342 // beneficial for it to be minimally dependent on other features.
armvixl5799d6c2014-05-01 11:05:00 +01002343 temps.Exclude(x0);
armvixlad96eda2013-06-14 11:42:37 +01002344 Label format_address;
2345 Adr(x0, &format_address);
2346
2347 // Emit the format string directly in the instruction stream.
armvixlc68cb642014-09-25 18:49:30 +01002348 {
armvixl5289c592015-03-02 13:52:04 +00002349 BlockPoolsScope scope(this);
armvixlc68cb642014-09-25 18:49:30 +01002350 // Data emitted:
2351 // branch
2352 // strlen(format) + 1 (includes null termination)
2353 // padding to next instruction
2354 // unreachable
armvixl0f35e362016-05-10 13:57:58 +01002355 EmissionCheckScope guard(this,
2356 AlignUp(strlen(format) + 1, kInstructionSize) +
2357 2 * kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002358 Label after_data;
2359 B(&after_data);
2360 Bind(&format_address);
armvixlc68cb642014-09-25 18:49:30 +01002361 EmitString(format);
armvixlad96eda2013-06-14 11:42:37 +01002362 Unreachable();
2363 Bind(&after_data);
2364 }
2365
2366 // We don't pass any arguments on the stack, but we still need to align the C
2367 // stack pointer to a 16-byte boundary for PCS compliance.
2368 if (!sp.Is(StackPointer())) {
2369 Bic(sp, StackPointer(), 0xf);
2370 }
2371
2372 // Actually call printf. This part needs special handling for the simulator,
2373 // since the system printf function will use a different instruction set and
2374 // the procedure-call standard will not be compatible.
armvixl684cd2a2015-10-23 13:38:33 +01002375 if (allow_simulator_instructions_) {
armvixlc68cb642014-09-25 18:49:30 +01002376 InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002377 hlt(kPrintfOpcode);
armvixl0f35e362016-05-10 13:57:58 +01002378 dc32(arg_count); // kPrintfArgCountOffset
armvixl5799d6c2014-05-01 11:05:00 +01002379
2380 // Determine the argument pattern.
2381 uint32_t arg_pattern_list = 0;
2382 for (int i = 0; i < arg_count; i++) {
2383 uint32_t arg_pattern;
2384 if (pcs[i].IsRegister()) {
2385 arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
2386 } else {
2387 VIXL_ASSERT(pcs[i].Is64Bits());
2388 arg_pattern = kPrintfArgD;
2389 }
2390 VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
2391 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
2392 }
armvixl0f35e362016-05-10 13:57:58 +01002393 dc32(arg_pattern_list); // kPrintfArgPatternListOffset
armvixl684cd2a2015-10-23 13:38:33 +01002394 } else {
2395 Register tmp = temps.AcquireX();
2396 Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2397 Blr(tmp);
armvixlad96eda2013-06-14 11:42:37 +01002398 }
armvixlad96eda2013-06-14 11:42:37 +01002399}
2400
2401
armvixl0f35e362016-05-10 13:57:58 +01002402void MacroAssembler::Printf(const char* format,
armvixl5799d6c2014-05-01 11:05:00 +01002403 CPURegister arg0,
2404 CPURegister arg1,
2405 CPURegister arg2,
2406 CPURegister arg3) {
2407 // We can only print sp if it is the current stack pointer.
2408 if (!sp.Is(StackPointer())) {
2409 VIXL_ASSERT(!sp.Aliases(arg0));
2410 VIXL_ASSERT(!sp.Aliases(arg1));
2411 VIXL_ASSERT(!sp.Aliases(arg2));
2412 VIXL_ASSERT(!sp.Aliases(arg3));
2413 }
2414
armvixlb0c8ae22014-03-21 14:03:59 +00002415 // Make sure that the macro assembler doesn't try to use any of our arguments
2416 // as scratch registers.
2417 UseScratchRegisterScope exclude_all(this);
2418 exclude_all.ExcludeAll();
2419
armvixlad96eda2013-06-14 11:42:37 +01002420 // Preserve all caller-saved registers as well as NZCV.
2421 // If sp is the stack pointer, PushCPURegList asserts that the size of each
2422 // list is a multiple of 16 bytes.
2423 PushCPURegList(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002424 PushCPURegList(kCallerSavedV);
armvixlad96eda2013-06-14 11:42:37 +01002425
armvixl0f35e362016-05-10 13:57:58 +01002426 {
2427 UseScratchRegisterScope temps(this);
armvixlb0c8ae22014-03-21 14:03:59 +00002428 // We can use caller-saved registers as scratch values (except for argN).
armvixl5799d6c2014-05-01 11:05:00 +01002429 temps.Include(kCallerSaved);
armvixl5289c592015-03-02 13:52:04 +00002430 temps.Include(kCallerSavedV);
armvixlb0c8ae22014-03-21 14:03:59 +00002431 temps.Exclude(arg0, arg1, arg2, arg3);
armvixlad96eda2013-06-14 11:42:37 +01002432
armvixl5799d6c2014-05-01 11:05:00 +01002433 // If any of the arguments are the current stack pointer, allocate a new
2434 // register for them, and adjust the value to compensate for pushing the
2435 // caller-saved registers.
2436 bool arg0_sp = StackPointer().Aliases(arg0);
2437 bool arg1_sp = StackPointer().Aliases(arg1);
2438 bool arg2_sp = StackPointer().Aliases(arg2);
2439 bool arg3_sp = StackPointer().Aliases(arg3);
2440 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
2441 // Allocate a register to hold the original stack pointer value, to pass
2442 // to PrintfNoPreserve as an argument.
2443 Register arg_sp = temps.AcquireX();
armvixl0f35e362016-05-10 13:57:58 +01002444 Add(arg_sp,
2445 StackPointer(),
armvixl5289c592015-03-02 13:52:04 +00002446 kCallerSaved.TotalSizeInBytes() + kCallerSavedV.TotalSizeInBytes());
armvixl5799d6c2014-05-01 11:05:00 +01002447 if (arg0_sp) arg0 = Register(arg_sp.code(), arg0.size());
2448 if (arg1_sp) arg1 = Register(arg_sp.code(), arg1.size());
2449 if (arg2_sp) arg2 = Register(arg_sp.code(), arg2.size());
2450 if (arg3_sp) arg3 = Register(arg_sp.code(), arg3.size());
2451 }
2452
armvixlb0c8ae22014-03-21 14:03:59 +00002453 // Preserve NZCV.
2454 Register tmp = temps.AcquireX();
2455 Mrs(tmp, NZCV);
2456 Push(tmp, xzr);
armvixl5799d6c2014-05-01 11:05:00 +01002457 temps.Release(tmp);
armvixlb0c8ae22014-03-21 14:03:59 +00002458
2459 PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2460
armvixl5799d6c2014-05-01 11:05:00 +01002461 // Restore NZCV.
2462 tmp = temps.AcquireX();
armvixlb0c8ae22014-03-21 14:03:59 +00002463 Pop(xzr, tmp);
2464 Msr(NZCV, tmp);
armvixl5799d6c2014-05-01 11:05:00 +01002465 temps.Release(tmp);
armvixlb0c8ae22014-03-21 14:03:59 +00002466 }
2467
armvixl5289c592015-03-02 13:52:04 +00002468 PopCPURegList(kCallerSavedV);
armvixlad96eda2013-06-14 11:42:37 +01002469 PopCPURegList(kCallerSaved);
2470}
2471
2472void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
armvixlb0c8ae22014-03-21 14:03:59 +00002473 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002474
armvixl684cd2a2015-10-23 13:38:33 +01002475 if (allow_simulator_instructions_) {
2476 // The arguments to the trace pseudo instruction need to be contiguous in
2477 // memory, so make sure we don't try to emit a literal pool.
2478 InstructionAccurateScope scope(this, kTraceLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002479
armvixl684cd2a2015-10-23 13:38:33 +01002480 Label start;
2481 bind(&start);
armvixlad96eda2013-06-14 11:42:37 +01002482
armvixl684cd2a2015-10-23 13:38:33 +01002483 // Refer to simulator-a64.h for a description of the marker and its
2484 // arguments.
2485 hlt(kTraceOpcode);
armvixlad96eda2013-06-14 11:42:37 +01002486
armvixl684cd2a2015-10-23 13:38:33 +01002487 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2488 dc32(parameters);
armvixlad96eda2013-06-14 11:42:37 +01002489
armvixl684cd2a2015-10-23 13:38:33 +01002490 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2491 dc32(command);
2492 } else {
2493 // Emit nothing on real hardware.
2494 USE(parameters, command);
2495 }
armvixlad96eda2013-06-14 11:42:37 +01002496}
2497
2498
2499void MacroAssembler::Log(TraceParameters parameters) {
armvixlb0c8ae22014-03-21 14:03:59 +00002500 VIXL_ASSERT(allow_macro_instructions_);
armvixlad96eda2013-06-14 11:42:37 +01002501
armvixl684cd2a2015-10-23 13:38:33 +01002502 if (allow_simulator_instructions_) {
2503 // The arguments to the log pseudo instruction need to be contiguous in
2504 // memory, so make sure we don't try to emit a literal pool.
2505 InstructionAccurateScope scope(this, kLogLength / kInstructionSize);
armvixlad96eda2013-06-14 11:42:37 +01002506
armvixl684cd2a2015-10-23 13:38:33 +01002507 Label start;
2508 bind(&start);
armvixlad96eda2013-06-14 11:42:37 +01002509
armvixl684cd2a2015-10-23 13:38:33 +01002510 // Refer to simulator-a64.h for a description of the marker and its
2511 // arguments.
2512 hlt(kLogOpcode);
armvixlad96eda2013-06-14 11:42:37 +01002513
armvixl684cd2a2015-10-23 13:38:33 +01002514 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2515 dc32(parameters);
2516 } else {
2517 // Emit nothing on real hardware.
2518 USE(parameters);
2519 }
armvixlad96eda2013-06-14 11:42:37 +01002520}
2521
armvixl578645f2013-08-15 17:21:42 +01002522
2523void MacroAssembler::EnableInstrumentation() {
armvixlb0c8ae22014-03-21 14:03:59 +00002524 VIXL_ASSERT(!isprint(InstrumentStateEnable));
armvixl578645f2013-08-15 17:21:42 +01002525 InstructionAccurateScope scope(this, 1);
2526 movn(xzr, InstrumentStateEnable);
2527}
2528
2529
2530void MacroAssembler::DisableInstrumentation() {
armvixlb0c8ae22014-03-21 14:03:59 +00002531 VIXL_ASSERT(!isprint(InstrumentStateDisable));
armvixl578645f2013-08-15 17:21:42 +01002532 InstructionAccurateScope scope(this, 1);
2533 movn(xzr, InstrumentStateDisable);
2534}
2535
2536
2537void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
armvixlb0c8ae22014-03-21 14:03:59 +00002538 VIXL_ASSERT(strlen(marker_name) == 2);
armvixl578645f2013-08-15 17:21:42 +01002539
2540 // We allow only printable characters in the marker names. Unprintable
2541 // characters are reserved for controlling features of the instrumentation.
armvixlb0c8ae22014-03-21 14:03:59 +00002542 VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
armvixl578645f2013-08-15 17:21:42 +01002543
2544 InstructionAccurateScope scope(this, 1);
2545 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
2546}
2547
armvixlb0c8ae22014-03-21 14:03:59 +00002548
armvixl330dc712014-11-25 10:38:32 +00002549void UseScratchRegisterScope::Open(MacroAssembler* masm) {
2550 VIXL_ASSERT(!initialised_);
armvixl0f35e362016-05-10 13:57:58 +01002551 VIXL_ASSERT(masm != NULL);
armvixl330dc712014-11-25 10:38:32 +00002552 available_ = masm->TmpList();
2553 availablefp_ = masm->FPTmpList();
2554 old_available_ = available_->list();
2555 old_availablefp_ = availablefp_->list();
2556 VIXL_ASSERT(available_->type() == CPURegister::kRegister);
armvixl5289c592015-03-02 13:52:04 +00002557 VIXL_ASSERT(availablefp_->type() == CPURegister::kVRegister);
armvixl330dc712014-11-25 10:38:32 +00002558#ifdef VIXL_DEBUG
2559 initialised_ = true;
2560#endif
2561}
2562
2563
2564void UseScratchRegisterScope::Close() {
2565 if (available_) {
2566 available_->set_list(old_available_);
2567 available_ = NULL;
2568 }
2569 if (availablefp_) {
2570 availablefp_->set_list(old_availablefp_);
2571 availablefp_ = NULL;
2572 }
2573#ifdef VIXL_DEBUG
2574 initialised_ = false;
2575#endif
2576}
2577
2578
2579UseScratchRegisterScope::UseScratchRegisterScope(MacroAssembler* masm) {
2580#ifdef VIXL_DEBUG
2581 initialised_ = false;
2582#endif
2583 Open(masm);
2584}
2585
2586// This allows deferred (and optional) initialisation of the scope.
2587UseScratchRegisterScope::UseScratchRegisterScope()
armvixl0f35e362016-05-10 13:57:58 +01002588 : available_(NULL),
2589 availablefp_(NULL),
2590 old_available_(0),
2591 old_availablefp_(0) {
armvixl330dc712014-11-25 10:38:32 +00002592#ifdef VIXL_DEBUG
2593 initialised_ = false;
2594#endif
2595}
2596
armvixl0f35e362016-05-10 13:57:58 +01002597UseScratchRegisterScope::~UseScratchRegisterScope() { Close(); }
armvixlb0c8ae22014-03-21 14:03:59 +00002598
2599
armvixl5799d6c2014-05-01 11:05:00 +01002600bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2601 return available_->IncludesAliasOf(reg) || availablefp_->IncludesAliasOf(reg);
2602}
2603
2604
armvixlb0c8ae22014-03-21 14:03:59 +00002605Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
2606 int code = AcquireNextAvailable(available_).code();
armvixl4a102ba2014-07-14 09:02:40 +01002607 return Register(code, reg.size());
armvixlb0c8ae22014-03-21 14:03:59 +00002608}
2609
2610
2611FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
2612 int code = AcquireNextAvailable(availablefp_).code();
armvixl4a102ba2014-07-14 09:02:40 +01002613 return FPRegister(code, reg.size());
armvixlb0c8ae22014-03-21 14:03:59 +00002614}
2615
2616
2617void UseScratchRegisterScope::Release(const CPURegister& reg) {
armvixl330dc712014-11-25 10:38:32 +00002618 VIXL_ASSERT(initialised_);
armvixlb0c8ae22014-03-21 14:03:59 +00002619 if (reg.IsRegister()) {
2620 ReleaseByCode(available_, reg.code());
2621 } else if (reg.IsFPRegister()) {
2622 ReleaseByCode(availablefp_, reg.code());
2623 } else {
2624 VIXL_ASSERT(reg.IsNone());
2625 }
2626}
2627
2628
armvixl5799d6c2014-05-01 11:05:00 +01002629void UseScratchRegisterScope::Include(const CPURegList& list) {
armvixl330dc712014-11-25 10:38:32 +00002630 VIXL_ASSERT(initialised_);
armvixl5799d6c2014-05-01 11:05:00 +01002631 if (list.type() == CPURegister::kRegister) {
2632 // Make sure that neither sp nor xzr are included the list.
2633 IncludeByRegList(available_, list.list() & ~(xzr.Bit() | sp.Bit()));
2634 } else {
armvixl5289c592015-03-02 13:52:04 +00002635 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
armvixl5799d6c2014-05-01 11:05:00 +01002636 IncludeByRegList(availablefp_, list.list());
2637 }
2638}
2639
2640
armvixlb0c8ae22014-03-21 14:03:59 +00002641void UseScratchRegisterScope::Include(const Register& reg1,
2642 const Register& reg2,
2643 const Register& reg3,
2644 const Register& reg4) {
armvixl330dc712014-11-25 10:38:32 +00002645 VIXL_ASSERT(initialised_);
armvixlb0c8ae22014-03-21 14:03:59 +00002646 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2647 // Make sure that neither sp nor xzr are included the list.
2648 include &= ~(xzr.Bit() | sp.Bit());
2649
2650 IncludeByRegList(available_, include);
2651}
2652
2653
2654void UseScratchRegisterScope::Include(const FPRegister& reg1,
2655 const FPRegister& reg2,
2656 const FPRegister& reg3,
2657 const FPRegister& reg4) {
2658 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2659 IncludeByRegList(availablefp_, include);
2660}
2661
2662
armvixl5799d6c2014-05-01 11:05:00 +01002663void UseScratchRegisterScope::Exclude(const CPURegList& list) {
2664 if (list.type() == CPURegister::kRegister) {
2665 ExcludeByRegList(available_, list.list());
2666 } else {
armvixl5289c592015-03-02 13:52:04 +00002667 VIXL_ASSERT(list.type() == CPURegister::kVRegister);
armvixl5799d6c2014-05-01 11:05:00 +01002668 ExcludeByRegList(availablefp_, list.list());
2669 }
2670}
2671
2672
armvixlb0c8ae22014-03-21 14:03:59 +00002673void UseScratchRegisterScope::Exclude(const Register& reg1,
2674 const Register& reg2,
2675 const Register& reg3,
2676 const Register& reg4) {
2677 RegList exclude = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2678 ExcludeByRegList(available_, exclude);
2679}
2680
2681
2682void UseScratchRegisterScope::Exclude(const FPRegister& reg1,
2683 const FPRegister& reg2,
2684 const FPRegister& reg3,
2685 const FPRegister& reg4) {
2686 RegList excludefp = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit();
2687 ExcludeByRegList(availablefp_, excludefp);
2688}
2689
2690
2691void UseScratchRegisterScope::Exclude(const CPURegister& reg1,
2692 const CPURegister& reg2,
2693 const CPURegister& reg3,
2694 const CPURegister& reg4) {
2695 RegList exclude = 0;
2696 RegList excludefp = 0;
2697
2698 const CPURegister regs[] = {reg1, reg2, reg3, reg4};
2699
2700 for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
2701 if (regs[i].IsRegister()) {
2702 exclude |= regs[i].Bit();
2703 } else if (regs[i].IsFPRegister()) {
2704 excludefp |= regs[i].Bit();
2705 } else {
2706 VIXL_ASSERT(regs[i].IsNone());
2707 }
2708 }
2709
2710 ExcludeByRegList(available_, exclude);
2711 ExcludeByRegList(availablefp_, excludefp);
2712}
2713
2714
2715void UseScratchRegisterScope::ExcludeAll() {
2716 ExcludeByRegList(available_, available_->list());
2717 ExcludeByRegList(availablefp_, availablefp_->list());
2718}
2719
2720
2721CPURegister UseScratchRegisterScope::AcquireNextAvailable(
2722 CPURegList* available) {
2723 VIXL_CHECK(!available->IsEmpty());
2724 CPURegister result = available->PopLowestIndex();
2725 VIXL_ASSERT(!AreAliased(result, xzr, sp));
2726 return result;
2727}
2728
2729
2730void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
2731 ReleaseByRegList(available, static_cast<RegList>(1) << code);
2732}
2733
2734
2735void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
2736 RegList regs) {
2737 available->set_list(available->list() | regs);
2738}
2739
2740
2741void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
2742 RegList regs) {
2743 available->set_list(available->list() | regs);
2744}
2745
2746
2747void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
2748 RegList exclude) {
2749 available->set_list(available->list() & ~exclude);
2750}
2751
armvixlad96eda2013-06-14 11:42:37 +01002752} // namespace vixl