macro-assembler-aarch32.cc revision 15985a2fcc72ce0ec5e19c410b444ceec899c11f
1// Copyright 2015, VIXL authors
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7//   * Redistributions of source code must retain the above copyright notice,
8//     this list of conditions and the following disclaimer.
9//   * Redistributions in binary form must reproduce the above copyright
10//     notice, this list of conditions and the following disclaimer in the
11//     documentation and/or other materials provided with the distribution.
12//   * Neither the name of ARM Limited nor the names of its contributors may
13//     be used to endorse or promote products derived from this software
14//     without 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
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26// POSSIBILITY OF SUCH DAMAGE.
27
28#include "aarch32/macro-assembler-aarch32.h"
29
30#define STRINGIFY(x) #x
31#define TOSTRING(x) STRINGIFY(x)
32
33#define CONTEXT_SCOPE \
34  ContextScope context(this, __FILE__ ":" TOSTRING(__LINE__))
35
36namespace vixl {
37namespace aarch32 {
38
39void UseScratchRegisterScope::Open(MacroAssembler* masm) {
40  VIXL_ASSERT((available_ == NULL) && (available_vfp_ == NULL));
41  available_ = masm->GetScratchRegisterList();
42  old_available_ = available_->GetList();
43  available_vfp_ = masm->GetScratchVRegisterList();
44  old_available_vfp_ = available_vfp_->GetList();
45}
46
47
48void UseScratchRegisterScope::Close() {
49  if (available_ != NULL) {
50    available_->SetList(old_available_);
51    available_ = NULL;
52  }
53  if (available_vfp_ != NULL) {
54    available_vfp_->SetList(old_available_vfp_);
55    available_vfp_ = NULL;
56  }
57}
58
59
60bool UseScratchRegisterScope::IsAvailable(const Register& reg) const {
61  VIXL_ASSERT(available_ != NULL);
62  VIXL_ASSERT(reg.IsValid());
63  return available_->Includes(reg);
64}
65
66
67bool UseScratchRegisterScope::IsAvailable(const VRegister& reg) const {
68  VIXL_ASSERT(available_vfp_ != NULL);
69  VIXL_ASSERT(reg.IsValid());
70  return available_vfp_->IncludesAllOf(reg);
71}
72
73
74Register UseScratchRegisterScope::Acquire() {
75  VIXL_ASSERT(available_ != NULL);
76  VIXL_CHECK(!available_->IsEmpty());
77  Register reg = available_->GetFirstAvailableRegister();
78  available_->Remove(reg);
79  return reg;
80}
81
82
83VRegister UseScratchRegisterScope::AcquireV(unsigned size_in_bits) {
84  switch (size_in_bits) {
85    case kSRegSizeInBits:
86      return AcquireS();
87    case kDRegSizeInBits:
88      return AcquireD();
89    case kQRegSizeInBits:
90      return AcquireQ();
91    default:
92      VIXL_UNREACHABLE();
93      return NoVReg;
94  }
95}
96
97
98QRegister UseScratchRegisterScope::AcquireQ() {
99  VIXL_ASSERT(available_vfp_ != NULL);
100  VIXL_CHECK(!available_vfp_->IsEmpty());
101  QRegister reg = available_vfp_->GetFirstAvailableQRegister();
102  available_vfp_->Remove(reg);
103  return reg;
104}
105
106
107DRegister UseScratchRegisterScope::AcquireD() {
108  VIXL_ASSERT(available_vfp_ != NULL);
109  VIXL_CHECK(!available_vfp_->IsEmpty());
110  DRegister reg = available_vfp_->GetFirstAvailableDRegister();
111  available_vfp_->Remove(reg);
112  return reg;
113}
114
115
116SRegister UseScratchRegisterScope::AcquireS() {
117  VIXL_ASSERT(available_vfp_ != NULL);
118  VIXL_CHECK(!available_vfp_->IsEmpty());
119  SRegister reg = available_vfp_->GetFirstAvailableSRegister();
120  available_vfp_->Remove(reg);
121  return reg;
122}
123
124
125void UseScratchRegisterScope::Release(const Register& reg) {
126  VIXL_ASSERT(available_ != NULL);
127  VIXL_ASSERT(reg.IsValid());
128  VIXL_ASSERT(!available_->Includes(reg));
129  available_->Combine(reg);
130}
131
132
133void UseScratchRegisterScope::Release(const VRegister& reg) {
134  VIXL_ASSERT(available_vfp_ != NULL);
135  VIXL_ASSERT(reg.IsValid());
136  VIXL_ASSERT(!available_vfp_->IncludesAliasOf(reg));
137  available_vfp_->Combine(reg);
138}
139
140
141void UseScratchRegisterScope::Include(const RegisterList& list) {
142  VIXL_ASSERT(available_ != NULL);
143  RegisterList excluded_registers(sp, lr, pc);
144  uint32_t mask = list.GetList() & ~excluded_registers.GetList();
145  available_->SetList(available_->GetList() | mask);
146}
147
148
149void UseScratchRegisterScope::Include(const VRegisterList& list) {
150  VIXL_ASSERT(available_vfp_ != NULL);
151  available_vfp_->SetList(available_vfp_->GetList() | list.GetList());
152}
153
154
155void UseScratchRegisterScope::Exclude(const RegisterList& list) {
156  VIXL_ASSERT(available_ != NULL);
157  available_->SetList(available_->GetList() & ~list.GetList());
158}
159
160
161void UseScratchRegisterScope::Exclude(const VRegisterList& list) {
162  VIXL_ASSERT(available_vfp_ != NULL);
163  available_vfp_->SetList(available_vfp_->GetList() & ~list.GetList());
164}
165
166
167void UseScratchRegisterScope::Exclude(const Operand& operand) {
168  if (operand.IsImmediateShiftedRegister()) {
169    Exclude(operand.GetBaseRegister());
170  } else if (operand.IsRegisterShiftedRegister()) {
171    Exclude(operand.GetBaseRegister(), operand.GetShiftRegister());
172  } else {
173    VIXL_ASSERT(operand.IsImmediate());
174  }
175}
176
177
178void UseScratchRegisterScope::ExcludeAll() {
179  if (available_ != NULL) {
180    available_->SetList(0);
181  }
182  if (available_vfp_ != NULL) {
183    available_vfp_->SetList(0);
184  }
185}
186
187
188void VeneerPoolManager::AddLabel(Label* label) {
189  if (last_label_reference_offset_ != 0) {
190    // If the pool grows faster than the instruction stream, we must adjust
191    // the checkpoint to compensate. The veneer pool entries take 32 bits, so
192    // this can only occur when two consecutive 16-bit instructions add veneer
193    // pool entries.
194    // This is typically the case for cbz and cbnz (other forward branches
195    // have a 32 bit variant which is always used).
196    if (last_label_reference_offset_ + 2 * k16BitT32InstructionSizeInBytes ==
197        static_cast<uint32_t>(masm_->GetCursorOffset())) {
198      // We found two 16 bit forward branches generated one after the other.
199      // That means that the pool will grow by one 32-bit branch when
200      // the cursor offset will move forward by only one 16-bit branch.
201      // Update the cbz/cbnz checkpoint to manage the difference.
202      near_checkpoint_ -=
203          k32BitT32InstructionSizeInBytes - k16BitT32InstructionSizeInBytes;
204    }
205  }
206  Label::ForwardReference& back = label->GetBackForwardRef();
207  VIXL_ASSERT(back.GetMaxForwardDistance() >= kCbzCbnzRange);
208  if (!label->IsInVeneerPool()) {
209    if (back.GetMaxForwardDistance() == kCbzCbnzRange) {
210      near_labels_.push_back(label);
211      label->SetVeneerPoolManager(this, true);
212    } else {
213      far_labels_.push_back(label);
214      label->SetVeneerPoolManager(this, false);
215    }
216  } else if (back.GetMaxForwardDistance() == kCbzCbnzRange) {
217    if (!label->IsNear()) {
218      far_labels_.remove(label);
219      near_labels_.push_back(label);
220      label->SetVeneerPoolManager(this, true);
221    }
222  }
223
224  back.SetIsBranch();
225  last_label_reference_offset_ = back.GetLocation();
226  label->UpdateCheckpoint();
227  Label::Offset tmp = label->GetCheckpoint();
228  if (label->IsNear()) {
229    if (near_checkpoint_ > tmp) near_checkpoint_ = tmp;
230  } else {
231    if (far_checkpoint_ > tmp) far_checkpoint_ = tmp;
232  }
233  // Always compute the global checkpoint as, adding veneers shorten the
234  // literals' checkpoint.
235  masm_->ComputeCheckpoint();
236}
237
238
239void VeneerPoolManager::RemoveLabel(Label* label) {
240  label->ClearVeneerPoolManager();
241  std::list<Label*>& list = label->IsNear() ? near_labels_ : far_labels_;
242  Label::Offset* checkpoint_reference =
243      label->IsNear() ? &near_checkpoint_ : &far_checkpoint_;
244  if (label->GetCheckpoint() == *checkpoint_reference) {
245    // We have to compute checkpoint again.
246    *checkpoint_reference = Label::kMaxOffset;
247    for (std::list<Label*>::iterator it = list.begin(); it != list.end();) {
248      if (*it == label) {
249        it = list.erase(it);
250      } else {
251        *checkpoint_reference =
252            std::min(*checkpoint_reference, (*it)->GetCheckpoint());
253        ++it;
254      }
255    }
256    masm_->ComputeCheckpoint();
257  } else {
258    // We only have to remove the label from the list.
259    list.remove(label);
260  }
261}
262
263
264void VeneerPoolManager::EmitLabel(Label* label, Label::Offset emitted_target) {
265  // Define the veneer.
266  Label veneer;
267  masm_->Bind(&veneer);
268  Label::Offset label_checkpoint = Label::kMaxOffset;
269  // Check all uses of this label.
270  for (Label::ForwardRefList::iterator ref = label->GetFirstForwardRef();
271       ref != label->GetEndForwardRef();) {
272    if (ref->IsBranch()) {
273      if (ref->GetCheckpoint() <= emitted_target) {
274        // Use the veneer.
275        masm_->EncodeLabelFor(*ref, &veneer);
276        ref = label->Erase(ref);
277      } else {
278        // Don't use the veneer => update checkpoint.
279        label_checkpoint = std::min(label_checkpoint, ref->GetCheckpoint());
280        ++ref;
281      }
282    } else {
283      ++ref;
284    }
285  }
286  label->SetCheckpoint(label_checkpoint);
287  if (label->IsNear()) {
288    near_checkpoint_ = std::min(near_checkpoint_, label_checkpoint);
289  } else {
290    far_checkpoint_ = std::min(far_checkpoint_, label_checkpoint);
291  }
292  // Generate the veneer.
293  masm_->B(label);
294}
295
296
297void VeneerPoolManager::Emit(Label::Offset target) {
298  VIXL_ASSERT(!IsBlocked());
299  // Sort labels (regarding their checkpoint) to avoid that a veneer
300  // becomes out of range. Near labels are always sorted as it holds only one
301  // range.
302  far_labels_.sort(Label::CompareLabels);
303  // To avoid too many veneers, generate veneers which will be necessary soon.
304  static const size_t kVeneerEmissionMargin = 1 * KBytes;
305  // To avoid too many veneers, use generated veneers for other not too far
306  // uses.
307  static const size_t kVeneerEmittedMargin = 2 * KBytes;
308  Label::Offset emitted_target = target + kVeneerEmittedMargin;
309  target += kVeneerEmissionMargin;
310  // Reset the checkpoints. They will be computed again in the loop.
311  near_checkpoint_ = Label::kMaxOffset;
312  far_checkpoint_ = Label::kMaxOffset;
313  for (std::list<Label*>::iterator it = near_labels_.begin();
314       it != near_labels_.end();) {
315    Label* label = *it;
316    // Move the label from the near list to the far list as it will be needed in
317    // the far list (as the veneer will generate a far branch).
318    // The label is pushed at the end of the list. The list remains sorted as
319    // we use an unconditional jump which has the biggest range. However, it
320    // wouldn't be a problem if the items at the end of the list were not
321    // sorted as they won't be used by this generation (their range will be
322    // greater than kVeneerEmittedMargin).
323    it = near_labels_.erase(it);
324    far_labels_.push_back(label);
325    label->SetVeneerPoolManager(this, false);
326    EmitLabel(label, emitted_target);
327  }
328  for (std::list<Label*>::iterator it = far_labels_.begin();
329       it != far_labels_.end();) {
330    // The labels are sorted. As soon as a veneer is not needed, we can stop.
331    if ((*it)->GetCheckpoint() > target) {
332      far_checkpoint_ = std::min(far_checkpoint_, (*it)->GetCheckpoint());
333      break;
334    }
335    // Even if we no longer have use of this label, we can keep it in the list
336    // as the next "B" would add it back.
337    EmitLabel(*it, emitted_target);
338    ++it;
339  }
340#ifdef VIXL_DEBUG
341  for (std::list<Label*>::iterator it = near_labels_.begin();
342       it != near_labels_.end();
343       ++it) {
344    VIXL_ASSERT((*it)->GetCheckpoint() >= near_checkpoint_);
345  }
346  for (std::list<Label*>::iterator it = far_labels_.begin();
347       it != far_labels_.end();
348       ++it) {
349    VIXL_ASSERT((*it)->GetCheckpoint() >= far_checkpoint_);
350  }
351#endif
352  masm_->ComputeCheckpoint();
353}
354
355
356// We use a subclass to access the protected `ExactAssemblyScope` constructor
357// giving us control over the pools, and make the constructor private to limit
358// usage to code paths emitting pools.
359class ExactAssemblyScopeWithoutPoolsCheck : public ExactAssemblyScope {
360 private:
361  ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler* masm,
362                                      size_t size,
363                                      SizePolicy size_policy = kExactSize)
364      : ExactAssemblyScope(masm,
365                           size,
366                           size_policy,
367                           ExactAssemblyScope::kIgnorePools) {}
368
369  friend void MacroAssembler::EmitLiteralPool(LiteralPool* const literal_pool,
370                                              EmitOption option);
371
372  // TODO: `PerformEnsureEmit` is `private`, so we have to make the
373  // `MacroAssembler` a friend.
374  friend class MacroAssembler;
375};
376
377
378void MacroAssembler::PerformEnsureEmit(Label::Offset target, uint32_t size) {
379  EmitOption option = kBranchRequired;
380  Label after_pools;
381  if (target > veneer_pool_manager_.GetCheckpoint()) {
382    {
383      ExactAssemblyScopeWithoutPoolsCheck
384          guard(this,
385                kMaxInstructionSizeInBytes,
386                ExactAssemblyScope::kMaximumSize);
387      b(&after_pools);
388    }
389    veneer_pool_manager_.Emit(target);
390    option = kNoBranchRequired;
391  }
392  // Check if the macro-assembler's internal literal pool should be emitted
393  // to avoid any overflow. If we already generated the veneers, we can
394  // emit the pool (the branch is already done).
395  VIXL_ASSERT(GetCursorOffset() <= literal_pool_manager_.GetCheckpoint());
396  if ((target > literal_pool_manager_.GetCheckpoint()) ||
397      (option == kNoBranchRequired)) {
398    // We will generate the literal pool. Generate all the veneers which
399    // would become out of range.
400    size_t literal_pool_size = literal_pool_manager_.GetLiteralPoolSize();
401    VIXL_ASSERT(IsInt32(literal_pool_size));
402    Label::Offset veneers_target =
403        target + static_cast<Label::Offset>(literal_pool_size);
404    VIXL_ASSERT(veneers_target >= 0);
405    if (veneers_target > veneer_pool_manager_.GetCheckpoint()) {
406      veneer_pool_manager_.Emit(veneers_target);
407    }
408    EmitLiteralPool(option);
409  }
410  BindHelper(&after_pools);
411  if (GetBuffer()->IsManaged()) {
412    bool grow_requested;
413    GetBuffer()->EnsureSpaceFor(size, &grow_requested);
414    if (grow_requested) ComputeCheckpoint();
415  }
416}
417
418
419void MacroAssembler::ComputeCheckpoint() {
420  checkpoint_ = veneer_pool_manager_.GetCheckpoint();
421  if (literal_pool_manager_.GetCheckpoint() != Label::kMaxOffset) {
422    size_t veneer_max_size = veneer_pool_manager_.GetMaxSize();
423    VIXL_ASSERT(IsInt32(veneer_max_size));
424    // We must be able to generate the pool and a branch over the pool.
425    Label::Offset tmp = literal_pool_manager_.GetCheckpoint() -
426                        static_cast<Label::Offset>(veneer_max_size +
427                                                   kMaxInstructionSizeInBytes);
428    VIXL_ASSERT(tmp >= 0);
429    checkpoint_ = std::min(checkpoint_, tmp);
430  }
431  size_t buffer_size = GetBuffer()->GetCapacity();
432  VIXL_ASSERT(IsInt32(buffer_size));
433  Label::Offset buffer_checkpoint = static_cast<Label::Offset>(buffer_size);
434  checkpoint_ = std::min(checkpoint_, buffer_checkpoint);
435}
436
437
438void MacroAssembler::EmitLiteralPool(LiteralPool* const literal_pool,
439                                     EmitOption option) {
440  if (literal_pool->GetSize() > 0) {
441#ifdef VIXL_DEBUG
442    for (LiteralPool::RawLiteralListIterator literal_it =
443             literal_pool->GetFirst();
444         literal_it != literal_pool->GetEnd();
445         literal_it++) {
446      RawLiteral* literal = *literal_it;
447      VIXL_ASSERT(GetCursorOffset() < literal->GetCheckpoint());
448    }
449#endif
450    Label after_literal;
451    if (option == kBranchRequired) {
452      GetBuffer()->EnsureSpaceFor(kMaxInstructionSizeInBytes);
453      VIXL_ASSERT(!AllowAssembler());
454      {
455        ExactAssemblyScopeWithoutPoolsCheck
456            guard(this,
457                  kMaxInstructionSizeInBytes,
458                  ExactAssemblyScope::kMaximumSize);
459        b(&after_literal);
460      }
461    }
462    GetBuffer()->Align();
463    GetBuffer()->EnsureSpaceFor(literal_pool->GetSize());
464    for (LiteralPool::RawLiteralListIterator it = literal_pool->GetFirst();
465         it != literal_pool->GetEnd();
466         it++) {
467      PlaceHelper(*it);
468      GetBuffer()->Align();
469    }
470    if (option == kBranchRequired) BindHelper(&after_literal);
471    literal_pool->Clear();
472  }
473}
474
475
476void MacroAssembler::Switch(Register reg, JumpTableBase* table) {
477  // 32-bit table A32:
478  // adr ip, table
479  // add ip, r1, lsl 2
480  // ldr ip, [ip]
481  // jmp: add pc, pc, ip, lsl 2
482  // table:
483  // .int (case_0 - (jmp + 8)) >> 2
484  // .int (case_1 - (jmp + 8)) >> 2
485  // .int (case_2 - (jmp + 8)) >> 2
486
487  // 16-bit table T32:
488  // adr ip, table
489  // jmp: tbh ip, r1
490  // table:
491  // .short (case_0 - (jmp + 4)) >> 1
492  // .short (case_1 - (jmp + 4)) >> 1
493  // .short (case_2 - (jmp + 4)) >> 1
494  // case_0:
495  //   ...
496  //   b end_switch
497  // case_1:
498  //   ...
499  //   b end_switch
500  // ...
501  // end_switch:
502  Label jump_table;
503  UseScratchRegisterScope temps(this);
504  Register scratch = temps.Acquire();
505  int table_size = AlignUp(table->GetTableSizeInBytes(), 4);
506
507  // Jump to default if reg is not in [0, table->GetLength()[
508  Cmp(reg, table->GetLength());
509  B(ge, table->GetDefaultLabel());
510
511  Adr(scratch, &jump_table);
512  if (IsUsingA32()) {
513    Add(scratch, scratch, Operand(reg, LSL, table->GetOffsetShift()));
514    switch (table->GetOffsetShift()) {
515      case 0:
516        Ldrb(scratch, MemOperand(scratch));
517        break;
518      case 1:
519        Ldrh(scratch, MemOperand(scratch));
520        break;
521      case 2:
522        Ldr(scratch, MemOperand(scratch));
523        break;
524      default:
525        VIXL_ABORT_WITH_MSG("Unsupported jump table size.\n");
526    }
527    // Emit whatever needs to be emitted if we want to
528    // correctly record the position of the branch instruction
529    uint32_t branch_location = GetCursorOffset();
530    table->SetBranchLocation(branch_location + GetArchitectureStatePCOffset());
531    ExactAssemblyScope scope(this,
532                             table_size + kA32InstructionSizeInBytes,
533                             ExactAssemblyScope::kMaximumSize);
534    add(pc, pc, Operand(scratch, LSL, 2));
535    VIXL_ASSERT((GetCursorOffset() - branch_location) == 4);
536    bind(&jump_table);
537    GenerateSwitchTable(table, table_size);
538  } else {
539    // Thumb mode - We have tbb and tbh to do this for 8 or 16bit offsets.
540    //  But for 32bit offsets, we use the same coding as for A32
541    if (table->GetOffsetShift() == 2) {
542      // 32bit offsets
543      Add(scratch, scratch, Operand(reg, LSL, 2));
544      Ldr(scratch, MemOperand(scratch));
545      // Cannot use add pc, pc, r lsl 1 as this is unpredictable in T32,
546      // so let's do the shift before
547      Lsl(scratch, scratch, 1);
548      // Emit whatever needs to be emitted if we want to
549      // correctly record the position of the branch instruction
550      uint32_t branch_location = GetCursorOffset();
551      table->SetBranchLocation(branch_location +
552                               GetArchitectureStatePCOffset());
553      ExactAssemblyScope scope(this,
554                               table_size + kMaxInstructionSizeInBytes,
555                               ExactAssemblyScope::kMaximumSize);
556      add(pc, pc, scratch);
557      // add pc, pc, rm fits in 16bit T2 (except for rm = sp)
558      VIXL_ASSERT((GetCursorOffset() - branch_location) == 2);
559      bind(&jump_table);
560      GenerateSwitchTable(table, table_size);
561    } else {
562      VIXL_ASSERT((table->GetOffsetShift() == 0) ||
563                  (table->GetOffsetShift() == 1));
564      // Emit whatever needs to be emitted if we want to
565      // correctly record the position of the branch instruction
566      uint32_t branch_location = GetCursorOffset();
567      table->SetBranchLocation(branch_location +
568                               GetArchitectureStatePCOffset());
569      ExactAssemblyScope scope(this,
570                               table_size + kMaxInstructionSizeInBytes,
571                               ExactAssemblyScope::kMaximumSize);
572      if (table->GetOffsetShift() == 0) {
573        // 8bit offsets
574        tbb(scratch, reg);
575      } else {
576        // 16bit offsets
577        tbh(scratch, reg);
578      }
579      // tbb/tbh is a 32bit instruction
580      VIXL_ASSERT((GetCursorOffset() - branch_location) == 4);
581      bind(&jump_table);
582      GenerateSwitchTable(table, table_size);
583    }
584  }
585}
586
587
588void MacroAssembler::GenerateSwitchTable(JumpTableBase* table, int table_size) {
589  table->BindTable(GetCursorOffset());
590  for (int i = 0; i < table_size / 4; i++) {
591    GetBuffer()->Emit32(0);
592  }
593}
594
595
596// switch/case/default : case
597// case_index is assumed to be < table->GetLength()
598// which is checked in JumpTable::Link and Table::SetPresenceBit
599void MacroAssembler::Case(JumpTableBase* table, int case_index) {
600  table->Link(this, case_index, GetCursorOffset());
601  table->SetPresenceBitForCase(case_index);
602}
603
604// switch/case/default : default
605void MacroAssembler::Default(JumpTableBase* table) {
606  Bind(table->GetDefaultLabel());
607}
608
609// switch/case/default : break
610void MacroAssembler::Break(JumpTableBase* table) { B(table->GetEndLabel()); }
611
612// switch/case/default : finalize
613// Manage the default path, mosstly. All empty offsets in the jumptable
614// will point to default.
615// All values not in [0, table->GetLength()[ are already pointing here anyway.
616void MacroAssembler::EndSwitch(JumpTableBase* table) { table->Finalize(this); }
617
618void MacroAssembler::HandleOutOfBoundsImmediate(Condition cond,
619                                                Register tmp,
620                                                uint32_t imm) {
621  if (IsUintN(16, imm)) {
622    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
623    mov(cond, tmp, imm & 0xffff);
624    return;
625  }
626  if (IsUsingT32()) {
627    if (ImmediateT32::IsImmediateT32(~imm)) {
628      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
629      mvn(cond, tmp, ~imm);
630      return;
631    }
632  } else {
633    if (ImmediateA32::IsImmediateA32(~imm)) {
634      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
635      mvn(cond, tmp, ~imm);
636      return;
637    }
638  }
639  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
640  mov(cond, tmp, imm & 0xffff);
641  movt(cond, tmp, imm >> 16);
642}
643
644
645void MacroAssembler::PadToMinimumBranchRange(Label* label) {
646  const Label::ForwardReference* last_reference = label->GetForwardRefBack();
647  if ((last_reference != NULL) && last_reference->IsUsingT32()) {
648    uint32_t location = last_reference->GetLocation();
649    if (location + k16BitT32InstructionSizeInBytes ==
650        static_cast<uint32_t>(GetCursorOffset())) {
651      uint16_t* instr_ptr = buffer_.GetOffsetAddress<uint16_t*>(location);
652      if ((instr_ptr[0] & kCbzCbnzMask) == kCbzCbnzValue) {
653        VIXL_ASSERT(!InITBlock());
654        // A Cbz or a Cbnz can't jump immediately after the instruction. If the
655        // target is immediately after the Cbz or Cbnz, we insert a nop to
656        // avoid that.
657        EmitT32_16(k16BitT32NopOpcode);
658      }
659    }
660  }
661}
662
663
664MemOperand MacroAssembler::MemOperandComputationHelper(
665    Condition cond,
666    Register scratch,
667    Register base,
668    uint32_t offset,
669    uint32_t extra_offset_mask) {
670  VIXL_ASSERT(!AliasesAvailableScratchRegister(scratch));
671  VIXL_ASSERT(!AliasesAvailableScratchRegister(base));
672  VIXL_ASSERT(allow_macro_instructions_);
673  VIXL_ASSERT(OutsideITBlock());
674
675  // Check for the simple pass-through case.
676  if ((offset & extra_offset_mask) == offset) return MemOperand(base, offset);
677
678  // If the base register is pc, the offset must be adjusted to account for the
679  // Align(pc, 4) in the original offset calculation. This alignment does not
680  // occur when the pc is read in 'add'.
681  if (base.IsPC() && !IsMultiple<4>(GetCursorOffset())) {
682    VIXL_ASSERT(IsMultiple<2>(GetCursorOffset()));
683    offset -= 2;
684  }
685
686  MacroEmissionCheckScope guard(this);
687  ITScope it_scope(this, &cond);
688
689  uint32_t load_store_offset = offset & extra_offset_mask;
690  uint32_t add_sub_offset = offset & ~extra_offset_mask;
691
692  add(cond, scratch, base, add_sub_offset);
693
694  return MemOperand(scratch, load_store_offset);
695}
696
697
698uint32_t MacroAssembler::GetOffsetMask(InstructionType type,
699                                       AddrMode addrmode) {
700  switch (type) {
701    case kLdr:
702    case kLdrb:
703    case kStr:
704    case kStrb:
705      if (IsUsingA32() || (addrmode == Offset)) {
706        return 0xfff;
707      } else {
708        return 0xff;
709      }
710    case kLdrsb:
711    case kLdrh:
712    case kLdrsh:
713    case kStrh:
714      if (IsUsingT32() && (addrmode == Offset)) {
715        return 0xfff;
716      } else {
717        return 0xff;
718      }
719    case kVldr:
720    case kVstr:
721      return 0x3fc;
722    case kLdrd:
723    case kStrd:
724      if (IsUsingA32()) {
725        return 0xff;
726      } else {
727        return 0x3fc;
728      }
729    default:
730      VIXL_UNREACHABLE();
731      return 0;
732  }
733}
734
735
736HARDFLOAT void PrintfTrampolineRRRR(
737    const char* format, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
738  printf(format, a, b, c, d);
739}
740
741
742HARDFLOAT void PrintfTrampolineRRRD(
743    const char* format, uint32_t a, uint32_t b, uint32_t c, double d) {
744  printf(format, a, b, c, d);
745}
746
747
748HARDFLOAT void PrintfTrampolineRRDR(
749    const char* format, uint32_t a, uint32_t b, double c, uint32_t d) {
750  printf(format, a, b, c, d);
751}
752
753
754HARDFLOAT void PrintfTrampolineRRDD(
755    const char* format, uint32_t a, uint32_t b, double c, double d) {
756  printf(format, a, b, c, d);
757}
758
759
760HARDFLOAT void PrintfTrampolineRDRR(
761    const char* format, uint32_t a, double b, uint32_t c, uint32_t d) {
762  printf(format, a, b, c, d);
763}
764
765
766HARDFLOAT void PrintfTrampolineRDRD(
767    const char* format, uint32_t a, double b, uint32_t c, double d) {
768  printf(format, a, b, c, d);
769}
770
771
772HARDFLOAT void PrintfTrampolineRDDR(
773    const char* format, uint32_t a, double b, double c, uint32_t d) {
774  printf(format, a, b, c, d);
775}
776
777
778HARDFLOAT void PrintfTrampolineRDDD(
779    const char* format, uint32_t a, double b, double c, double d) {
780  printf(format, a, b, c, d);
781}
782
783
784HARDFLOAT void PrintfTrampolineDRRR(
785    const char* format, double a, uint32_t b, uint32_t c, uint32_t d) {
786  printf(format, a, b, c, d);
787}
788
789
790HARDFLOAT void PrintfTrampolineDRRD(
791    const char* format, double a, uint32_t b, uint32_t c, double d) {
792  printf(format, a, b, c, d);
793}
794
795
796HARDFLOAT void PrintfTrampolineDRDR(
797    const char* format, double a, uint32_t b, double c, uint32_t d) {
798  printf(format, a, b, c, d);
799}
800
801
802HARDFLOAT void PrintfTrampolineDRDD(
803    const char* format, double a, uint32_t b, double c, double d) {
804  printf(format, a, b, c, d);
805}
806
807
808HARDFLOAT void PrintfTrampolineDDRR(
809    const char* format, double a, double b, uint32_t c, uint32_t d) {
810  printf(format, a, b, c, d);
811}
812
813
814HARDFLOAT void PrintfTrampolineDDRD(
815    const char* format, double a, double b, uint32_t c, double d) {
816  printf(format, a, b, c, d);
817}
818
819
820HARDFLOAT void PrintfTrampolineDDDR(
821    const char* format, double a, double b, double c, uint32_t d) {
822  printf(format, a, b, c, d);
823}
824
825
826HARDFLOAT void PrintfTrampolineDDDD(
827    const char* format, double a, double b, double c, double d) {
828  printf(format, a, b, c, d);
829}
830
831
832void MacroAssembler::Printf(const char* format,
833                            CPURegister reg1,
834                            CPURegister reg2,
835                            CPURegister reg3,
836                            CPURegister reg4) {
837  if (generate_simulator_code_) {
838    PushRegister(reg4);
839    PushRegister(reg3);
840    PushRegister(reg2);
841    PushRegister(reg1);
842    Push(RegisterList(r0, r1));
843    StringLiteral* format_literal =
844        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
845    Adr(r0, format_literal);
846    uint32_t args = (reg4.GetType() << 12) | (reg3.GetType() << 8) |
847                    (reg2.GetType() << 4) | reg1.GetType();
848    Mov(r1, args);
849    Hvc(kPrintfCode);
850    Pop(RegisterList(r0, r1));
851    int size = reg4.GetRegSizeInBytes() + reg3.GetRegSizeInBytes() +
852               reg2.GetRegSizeInBytes() + reg1.GetRegSizeInBytes();
853    Drop(size);
854  } else {
855    // Generate on a native platform => 32 bit environment.
856    // Preserve core registers r0-r3, r12, r14
857    const uint32_t saved_registers_mask =
858        kCallerSavedRegistersMask | (1 << r5.GetCode());
859    Push(RegisterList(saved_registers_mask));
860    // Push VFP registers.
861    Vpush(Untyped64, DRegisterList(d0, 8));
862    if (Has32DRegs()) Vpush(Untyped64, DRegisterList(d16, 16));
863    // Search one register which has been saved and which doesn't need to be
864    // printed.
865    RegisterList available_registers(kCallerSavedRegistersMask);
866    if (reg1.GetType() == CPURegister::kRRegister) {
867      available_registers.Remove(Register(reg1.GetCode()));
868    }
869    if (reg2.GetType() == CPURegister::kRRegister) {
870      available_registers.Remove(Register(reg2.GetCode()));
871    }
872    if (reg3.GetType() == CPURegister::kRRegister) {
873      available_registers.Remove(Register(reg3.GetCode()));
874    }
875    if (reg4.GetType() == CPURegister::kRRegister) {
876      available_registers.Remove(Register(reg4.GetCode()));
877    }
878    Register tmp = available_registers.GetFirstAvailableRegister();
879    VIXL_ASSERT(tmp.GetType() == CPURegister::kRRegister);
880    // Push the flags.
881    Mrs(tmp, APSR);
882    Push(tmp);
883    Vmrs(RegisterOrAPSR_nzcv(tmp.GetCode()), FPSCR);
884    Push(tmp);
885    // Push the registers to print on the stack.
886    PushRegister(reg4);
887    PushRegister(reg3);
888    PushRegister(reg2);
889    PushRegister(reg1);
890    int core_count = 1;
891    int vfp_count = 0;
892    uint32_t printf_type = 0;
893    // Pop the registers to print and store them into r1-r3 and/or d0-d3.
894    // Reg4 may stay into the stack if all the register to print are core
895    // registers.
896    PreparePrintfArgument(reg1, &core_count, &vfp_count, &printf_type);
897    PreparePrintfArgument(reg2, &core_count, &vfp_count, &printf_type);
898    PreparePrintfArgument(reg3, &core_count, &vfp_count, &printf_type);
899    PreparePrintfArgument(reg4, &core_count, &vfp_count, &printf_type);
900    // Ensure that the stack is aligned on 8 bytes.
901    And(r5, sp, 0x7);
902    if (core_count == 5) {
903      // One 32 bit argument (reg4) has been left on the stack =>  align the
904      // stack
905      // before the argument.
906      Pop(r0);
907      Sub(sp, sp, r5);
908      Push(r0);
909    } else {
910      Sub(sp, sp, r5);
911    }
912    // Select the right trampoline depending on the arguments.
913    uintptr_t address;
914    switch (printf_type) {
915      case 0:
916        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
917        break;
918      case 1:
919        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRR);
920        break;
921      case 2:
922        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRR);
923        break;
924      case 3:
925        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRR);
926        break;
927      case 4:
928        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDR);
929        break;
930      case 5:
931        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDR);
932        break;
933      case 6:
934        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDR);
935        break;
936      case 7:
937        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDR);
938        break;
939      case 8:
940        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRD);
941        break;
942      case 9:
943        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRD);
944        break;
945      case 10:
946        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRD);
947        break;
948      case 11:
949        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRD);
950        break;
951      case 12:
952        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDD);
953        break;
954      case 13:
955        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDD);
956        break;
957      case 14:
958        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDD);
959        break;
960      case 15:
961        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDD);
962        break;
963      default:
964        VIXL_UNREACHABLE();
965        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
966        break;
967    }
968    StringLiteral* format_literal =
969        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
970    Adr(r0, format_literal);
971    Mov(ip, Operand::From(address));
972    Blx(ip);
973    // If register reg4 was left on the stack => skip it.
974    if (core_count == 5) Drop(kRegSizeInBytes);
975    // Restore the stack as it was before alignment.
976    Add(sp, sp, r5);
977    // Restore the flags.
978    Pop(tmp);
979    Vmsr(FPSCR, tmp);
980    Pop(tmp);
981    Msr(APSR_nzcvqg, tmp);
982    // Restore the regsisters.
983    if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
984    Vpop(Untyped64, DRegisterList(d0, 8));
985    Pop(RegisterList(saved_registers_mask));
986  }
987}
988
989
990void MacroAssembler::PushRegister(CPURegister reg) {
991  switch (reg.GetType()) {
992    case CPURegister::kNoRegister:
993      break;
994    case CPURegister::kRRegister:
995      Push(Register(reg.GetCode()));
996      break;
997    case CPURegister::kSRegister:
998      Vpush(Untyped32, SRegisterList(SRegister(reg.GetCode())));
999      break;
1000    case CPURegister::kDRegister:
1001      Vpush(Untyped64, DRegisterList(DRegister(reg.GetCode())));
1002      break;
1003    case CPURegister::kQRegister:
1004      VIXL_UNIMPLEMENTED();
1005      break;
1006  }
1007}
1008
1009
1010void MacroAssembler::PreparePrintfArgument(CPURegister reg,
1011                                           int* core_count,
1012                                           int* vfp_count,
1013                                           uint32_t* printf_type) {
1014  switch (reg.GetType()) {
1015    case CPURegister::kNoRegister:
1016      break;
1017    case CPURegister::kRRegister:
1018      VIXL_ASSERT(*core_count <= 4);
1019      if (*core_count < 4) Pop(Register(*core_count));
1020      *core_count += 1;
1021      break;
1022    case CPURegister::kSRegister:
1023      VIXL_ASSERT(*vfp_count < 4);
1024      *printf_type |= 1 << (*core_count + *vfp_count - 1);
1025      Vpop(Untyped32, SRegisterList(SRegister(*vfp_count * 2)));
1026      Vcvt(F64, F32, DRegister(*vfp_count), SRegister(*vfp_count * 2));
1027      *vfp_count += 1;
1028      break;
1029    case CPURegister::kDRegister:
1030      VIXL_ASSERT(*vfp_count < 4);
1031      *printf_type |= 1 << (*core_count + *vfp_count - 1);
1032      Vpop(Untyped64, DRegisterList(DRegister(*vfp_count)));
1033      *vfp_count += 1;
1034      break;
1035    case CPURegister::kQRegister:
1036      VIXL_UNIMPLEMENTED();
1037      break;
1038  }
1039}
1040
1041
1042void MacroAssembler::Delegate(InstructionType type,
1043                              InstructionCondROp instruction,
1044                              Condition cond,
1045                              Register rn,
1046                              const Operand& operand) {
1047  // movt, sxtb16, teq, uxtb16
1048  VIXL_ASSERT((type == kMovt) || (type == kSxtb16) || (type == kTeq) ||
1049              (type == kUxtb16));
1050
1051  if (type == kMovt) {
1052    VIXL_ABORT_WITH_MSG("`Movt` expects a 16-bit immediate.");
1053  }
1054
1055  // This delegate only supports teq with immediates.
1056  CONTEXT_SCOPE;
1057  if ((type == kTeq) && operand.IsImmediate()) {
1058    UseScratchRegisterScope temps(this);
1059    Register scratch = temps.Acquire();
1060    HandleOutOfBoundsImmediate(cond, scratch, operand.GetImmediate());
1061    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1062    teq(cond, rn, scratch);
1063    return;
1064  }
1065  Assembler::Delegate(type, instruction, cond, rn, operand);
1066}
1067
1068
1069void MacroAssembler::Delegate(InstructionType type,
1070                              InstructionCondSizeROp instruction,
1071                              Condition cond,
1072                              EncodingSize size,
1073                              Register rn,
1074                              const Operand& operand) {
1075  // cmn cmp mov movs mvn mvns sxtb sxth tst uxtb uxth
1076  CONTEXT_SCOPE;
1077  VIXL_ASSERT(size.IsBest());
1078  VIXL_ASSERT((type == kCmn) || (type == kCmp) || (type == kMov) ||
1079              (type == kMovs) || (type == kMvn) || (type == kMvns) ||
1080              (type == kSxtb) || (type == kSxth) || (type == kTst) ||
1081              (type == kUxtb) || (type == kUxth));
1082  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
1083    VIXL_ASSERT((type != kMov) || (type != kMovs));
1084    InstructionCondRROp shiftop = NULL;
1085    switch (operand.GetShift().GetType()) {
1086      case LSL:
1087        shiftop = &Assembler::lsl;
1088        break;
1089      case LSR:
1090        shiftop = &Assembler::lsr;
1091        break;
1092      case ASR:
1093        shiftop = &Assembler::asr;
1094        break;
1095      case RRX:
1096        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1097        VIXL_UNREACHABLE();
1098        break;
1099      case ROR:
1100        shiftop = &Assembler::ror;
1101        break;
1102      default:
1103        VIXL_UNREACHABLE();
1104    }
1105    if (shiftop != NULL) {
1106      UseScratchRegisterScope temps(this);
1107      Register scratch = temps.Acquire();
1108      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1109      (this->*shiftop)(cond,
1110                       scratch,
1111                       operand.GetBaseRegister(),
1112                       operand.GetShiftRegister());
1113      (this->*instruction)(cond, size, rn, scratch);
1114      return;
1115    }
1116  }
1117  if (operand.IsImmediate()) {
1118    uint32_t imm = operand.GetImmediate();
1119    switch (type) {
1120      case kMov:
1121      case kMovs:
1122        if (!rn.IsPC()) {
1123          // Immediate is too large, but not using PC, so handle with mov{t}.
1124          HandleOutOfBoundsImmediate(cond, rn, imm);
1125          if (type == kMovs) {
1126            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1127            tst(cond, rn, rn);
1128          }
1129          return;
1130        } else if (type == kMov) {
1131          VIXL_ASSERT(IsUsingA32() || cond.Is(al));
1132          // Immediate is too large and using PC, so handle using a temporary
1133          // register.
1134          UseScratchRegisterScope temps(this);
1135          Register scratch = temps.Acquire();
1136          HandleOutOfBoundsImmediate(al, scratch, imm);
1137          EnsureEmitFor(kMaxInstructionSizeInBytes);
1138          bx(cond, scratch);
1139          return;
1140        }
1141        break;
1142      case kCmn:
1143      case kCmp:
1144        if (IsUsingA32() || !rn.IsPC()) {
1145          UseScratchRegisterScope temps(this);
1146          Register scratch = temps.Acquire();
1147          HandleOutOfBoundsImmediate(cond, scratch, imm);
1148          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1149          (this->*instruction)(cond, size, rn, scratch);
1150          return;
1151        }
1152        break;
1153      case kMvn:
1154      case kMvns:
1155        if (!rn.IsPC()) {
1156          UseScratchRegisterScope temps(this);
1157          Register scratch = temps.Acquire();
1158          HandleOutOfBoundsImmediate(cond, scratch, imm);
1159          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1160          (this->*instruction)(cond, size, rn, scratch);
1161          return;
1162        }
1163        break;
1164      case kTst:
1165        if (IsUsingA32() || !rn.IsPC()) {
1166          UseScratchRegisterScope temps(this);
1167          Register scratch = temps.Acquire();
1168          HandleOutOfBoundsImmediate(cond, scratch, imm);
1169          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1170          (this->*instruction)(cond, size, rn, scratch);
1171          return;
1172        }
1173        break;
1174      default:  // kSxtb, Sxth, Uxtb, Uxth
1175        break;
1176    }
1177  }
1178  Assembler::Delegate(type, instruction, cond, size, rn, operand);
1179}
1180
1181
1182void MacroAssembler::Delegate(InstructionType type,
1183                              InstructionCondRROp instruction,
1184                              Condition cond,
1185                              Register rd,
1186                              Register rn,
1187                              const Operand& operand) {
1188  // orn orns pkhbt pkhtb rsc rscs sxtab sxtab16 sxtah uxtab uxtab16 uxtah
1189
1190  if ((type == kSxtab) || (type == kSxtab16) || (type == kSxtah) ||
1191      (type == kUxtab) || (type == kUxtab16) || (type == kUxtah) ||
1192      (type == kPkhbt) || (type == kPkhtb)) {
1193    UnimplementedDelegate(type);
1194    return;
1195  }
1196
1197  // This delegate only handles the following instructions.
1198  VIXL_ASSERT((type == kOrn) || (type == kOrns) || (type == kRsc) ||
1199              (type == kRscs));
1200  CONTEXT_SCOPE;
1201
1202  // T32 does not support register shifted register operands, emulate it.
1203  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
1204    InstructionCondRROp shiftop = NULL;
1205    switch (operand.GetShift().GetType()) {
1206      case LSL:
1207        shiftop = &Assembler::lsl;
1208        break;
1209      case LSR:
1210        shiftop = &Assembler::lsr;
1211        break;
1212      case ASR:
1213        shiftop = &Assembler::asr;
1214        break;
1215      case RRX:
1216        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1217        VIXL_UNREACHABLE();
1218        break;
1219      case ROR:
1220        shiftop = &Assembler::ror;
1221        break;
1222      default:
1223        VIXL_UNREACHABLE();
1224    }
1225    if (shiftop != NULL) {
1226      UseScratchRegisterScope temps(this);
1227      Register rm = operand.GetBaseRegister();
1228      Register rs = operand.GetShiftRegister();
1229      // Try to use rd as a scratch register. We can do this if it aliases rs or
1230      // rm (because we read them in the first instruction), but not rn.
1231      if (!rd.Is(rn)) temps.Include(rd);
1232      Register scratch = temps.Acquire();
1233      // TODO: The scope length was measured empirically. We should analyse the
1234      // worst-case size and add targetted tests.
1235      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1236      (this->*shiftop)(cond, scratch, rm, rs);
1237      (this->*instruction)(cond, rd, rn, scratch);
1238      return;
1239    }
1240  }
1241
1242  // T32 does not have a Rsc instruction, negate the lhs input and turn it into
1243  // an Adc. Adc and Rsc are equivalent using a bitwise NOT:
1244  //   adc rd, rn, operand <-> rsc rd, NOT(rn), operand
1245  if (IsUsingT32() && ((type == kRsc) || (type == kRscs))) {
1246    // The RegisterShiftRegister case should have been handled above.
1247    VIXL_ASSERT(!operand.IsRegisterShiftedRegister());
1248    UseScratchRegisterScope temps(this);
1249    // Try to use rd as a scratch register. We can do this if it aliases rn
1250    // (because we read it in the first instruction), but not rm.
1251    temps.Include(rd);
1252    temps.Exclude(operand);
1253    Register negated_rn = temps.Acquire();
1254    {
1255      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1256      mvn(cond, negated_rn, rn);
1257    }
1258    if (type == kRsc) {
1259      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1260      adc(cond, rd, negated_rn, operand);
1261      return;
1262    }
1263    // TODO: We shouldn't have to specify how much space the next instruction
1264    // needs.
1265    CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1266    adcs(cond, rd, negated_rn, operand);
1267    return;
1268  }
1269
1270  // A32 does not have a Orn instruction, negate the rhs input and turn it into
1271  // a Orr.
1272  if (IsUsingA32() && ((type == kOrn) || (type == kOrns))) {
1273    // TODO: orn r0, r1, imm -> orr r0, r1, neg(imm) if doable
1274    //  mvn r0, r2
1275    //  orr r0, r1, r0
1276    Register scratch;
1277    UseScratchRegisterScope temps(this);
1278    // Try to use rd as a scratch register. We can do this if it aliases rs or
1279    // rm (because we read them in the first instruction), but not rn.
1280    if (!rd.Is(rn)) temps.Include(rd);
1281    scratch = temps.Acquire();
1282    {
1283      // TODO: We shouldn't have to specify how much space the next instruction
1284      // needs.
1285      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1286      mvn(cond, scratch, operand);
1287    }
1288    if (type == kOrns) {
1289      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1290      orrs(cond, rd, rn, scratch);
1291      return;
1292    }
1293    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1294    orr(cond, rd, rn, scratch);
1295    return;
1296  }
1297  if (operand.IsImmediate()) {
1298    int32_t imm = operand.GetSignedImmediate();
1299
1300    // If the immediate can be encoded when inverted, turn Orn into Orr.
1301    // Otherwise rely on HandleOutOfBoundsImmediate to generate a series of
1302    // mov.
1303    if (IsUsingT32() && ((type == kOrn) || (type == kOrns)) &&
1304        ImmediateT32::IsImmediateT32(~imm)) {
1305      VIXL_ASSERT((type == kOrn) || (type == kOrns));
1306      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1307      switch (type) {
1308        case kOrn:
1309          orr(cond, rd, rn, ~imm);
1310          return;
1311        case kOrns:
1312          orrs(cond, rd, rn, ~imm);
1313          return;
1314        default:
1315          VIXL_UNREACHABLE();
1316          break;
1317      }
1318    } else {
1319      UseScratchRegisterScope temps(this);
1320      // Allow using the destination as a scratch register if possible.
1321      if (!rd.Is(rn)) temps.Include(rd);
1322      Register scratch = temps.Acquire();
1323      HandleOutOfBoundsImmediate(cond, scratch, imm);
1324      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1325      (this->*instruction)(cond, rd, rn, scratch);
1326      return;
1327    }
1328  }
1329  Assembler::Delegate(type, instruction, cond, rd, rn, operand);
1330}
1331
1332
1333void MacroAssembler::Delegate(InstructionType type,
1334                              InstructionCondSizeRL instruction,
1335                              Condition cond,
1336                              EncodingSize size,
1337                              Register rd,
1338                              Label* label) {
1339  VIXL_ASSERT((type == kLdr) || (type == kAdr));
1340
1341  CONTEXT_SCOPE;
1342  VIXL_ASSERT(size.IsBest());
1343
1344  if ((type == kLdr) && label->IsBound()) {
1345    CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1346    UseScratchRegisterScope temps(this);
1347    temps.Include(rd);
1348    uint32_t mask = GetOffsetMask(type, Offset);
1349    ldr(rd, MemOperandComputationHelper(cond, temps.Acquire(), label, mask));
1350    return;
1351  }
1352
1353  Assembler::Delegate(type, instruction, cond, size, rd, label);
1354}
1355
1356
1357void MacroAssembler::Delegate(InstructionType type,
1358                              InstructionCondSizeRROp instruction,
1359                              Condition cond,
1360                              EncodingSize size,
1361                              Register rd,
1362                              Register rn,
1363                              const Operand& operand) {
1364  // adc adcs add adds and_ ands asr asrs bic bics eor eors lsl lsls lsr lsrs
1365  // orr orrs ror rors rsb rsbs sbc sbcs sub subs
1366
1367  VIXL_ASSERT(
1368      (type == kAdc) || (type == kAdcs) || (type == kAdd) || (type == kAdds) ||
1369      (type == kAnd) || (type == kAnds) || (type == kAsr) || (type == kAsrs) ||
1370      (type == kBic) || (type == kBics) || (type == kEor) || (type == kEors) ||
1371      (type == kLsl) || (type == kLsls) || (type == kLsr) || (type == kLsrs) ||
1372      (type == kOrr) || (type == kOrrs) || (type == kRor) || (type == kRors) ||
1373      (type == kRsb) || (type == kRsbs) || (type == kSbc) || (type == kSbcs) ||
1374      (type == kSub) || (type == kSubs));
1375
1376  CONTEXT_SCOPE;
1377  VIXL_ASSERT(size.IsBest());
1378  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
1379    InstructionCondRROp shiftop = NULL;
1380    switch (operand.GetShift().GetType()) {
1381      case LSL:
1382        shiftop = &Assembler::lsl;
1383        break;
1384      case LSR:
1385        shiftop = &Assembler::lsr;
1386        break;
1387      case ASR:
1388        shiftop = &Assembler::asr;
1389        break;
1390      case RRX:
1391        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1392        VIXL_UNREACHABLE();
1393        break;
1394      case ROR:
1395        shiftop = &Assembler::ror;
1396        break;
1397      default:
1398        VIXL_UNREACHABLE();
1399    }
1400    if (shiftop != NULL) {
1401      UseScratchRegisterScope temps(this);
1402      Register rm = operand.GetBaseRegister();
1403      Register rs = operand.GetShiftRegister();
1404      // Try to use rd as a scratch register. We can do this if it aliases rs or
1405      // rm (because we read them in the first instruction), but not rn.
1406      if (!rd.Is(rn)) temps.Include(rd);
1407      Register scratch = temps.Acquire();
1408      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1409      (this->*shiftop)(cond, scratch, rm, rs);
1410      (this->*instruction)(cond, size, rd, rn, scratch);
1411      return;
1412    }
1413  }
1414  if (operand.IsImmediate()) {
1415    int32_t imm = operand.GetSignedImmediate();
1416    if (ImmediateT32::IsImmediateT32(~imm)) {
1417      if (IsUsingT32()) {
1418        switch (type) {
1419          case kOrr:
1420            orn(cond, rd, rn, ~imm);
1421            return;
1422          case kOrrs:
1423            orns(cond, rd, rn, ~imm);
1424            return;
1425          default:
1426            break;
1427        }
1428      }
1429    }
1430    if (imm < 0) {
1431      InstructionCondSizeRROp asmcb = NULL;
1432      // Add and sub are equivalent using an arithmetic negation:
1433      //   add rd, rn, #imm <-> sub rd, rn, - #imm
1434      // Add and sub with carry are equivalent using a bitwise NOT:
1435      //   adc rd, rn, #imm <-> sbc rd, rn, NOT #imm
1436      switch (type) {
1437        case kAdd:
1438          asmcb = &Assembler::sub;
1439          imm = -imm;
1440          break;
1441        case kAdds:
1442          asmcb = &Assembler::subs;
1443          imm = -imm;
1444          break;
1445        case kSub:
1446          asmcb = &Assembler::add;
1447          imm = -imm;
1448          break;
1449        case kSubs:
1450          asmcb = &Assembler::adds;
1451          imm = -imm;
1452          break;
1453        case kAdc:
1454          asmcb = &Assembler::sbc;
1455          imm = ~imm;
1456          break;
1457        case kAdcs:
1458          asmcb = &Assembler::sbcs;
1459          imm = ~imm;
1460          break;
1461        case kSbc:
1462          asmcb = &Assembler::adc;
1463          imm = ~imm;
1464          break;
1465        case kSbcs:
1466          asmcb = &Assembler::adcs;
1467          imm = ~imm;
1468          break;
1469        default:
1470          break;
1471      }
1472      if (asmcb != NULL) {
1473        CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1474        (this->*asmcb)(cond, size, rd, rn, Operand(imm));
1475        return;
1476      }
1477    }
1478    UseScratchRegisterScope temps(this);
1479    // Allow using the destination as a scratch register if possible.
1480    if (!rd.Is(rn)) temps.Include(rd);
1481
1482    if (rn.IsPC()) {
1483      // If we're reading the PC, we need to do it in the first instruction,
1484      // otherwise we'll read the wrong value. We rely on this to handle the
1485      // long-range PC-relative MemOperands which can result from user-managed
1486      // literals.
1487
1488      // Only handle negative offsets. The correct way to handle positive
1489      // offsets isn't clear; does the user want the offset from the start of
1490      // the macro, or from the end (to allow a certain amount of space)?
1491      bool offset_is_negative_or_zero = (imm <= 0);
1492      switch (type) {
1493        case kAdd:
1494        case kAdds:
1495          offset_is_negative_or_zero = (imm <= 0);
1496          break;
1497        case kSub:
1498        case kSubs:
1499          offset_is_negative_or_zero = (imm >= 0);
1500          break;
1501        case kAdc:
1502        case kAdcs:
1503          offset_is_negative_or_zero = (imm < 0);
1504          break;
1505        case kSbc:
1506        case kSbcs:
1507          offset_is_negative_or_zero = (imm > 0);
1508          break;
1509        default:
1510          break;
1511      }
1512      if (offset_is_negative_or_zero) {
1513        {
1514          rn = temps.Acquire();
1515          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1516          mov(cond, rn, pc);
1517        }
1518        // Recurse rather than falling through, to try to get the immediate into
1519        // a single instruction.
1520        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1521        (this->*instruction)(cond, size, rd, rn, operand);
1522        return;
1523      }
1524    } else {
1525      Register scratch = temps.Acquire();
1526      // TODO: The scope length was measured empirically. We should analyse the
1527      // worst-case size and add targetted tests.
1528      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1529      mov(cond, scratch, operand.GetImmediate());
1530      (this->*instruction)(cond, size, rd, rn, scratch);
1531      return;
1532    }
1533  }
1534  Assembler::Delegate(type, instruction, cond, size, rd, rn, operand);
1535}
1536
1537
1538void MacroAssembler::Delegate(InstructionType type,
1539                              InstructionRL instruction,
1540                              Register rn,
1541                              Label* label) {
1542  // cbz cbnz
1543  VIXL_ASSERT((type == kCbz) || (type == kCbnz));
1544
1545  CONTEXT_SCOPE;
1546  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1547  if (IsUsingA32()) {
1548    if (type == kCbz) {
1549      VIXL_ABORT_WITH_MSG("Cbz is only available for T32.\n");
1550    } else {
1551      VIXL_ABORT_WITH_MSG("Cbnz is only available for T32.\n");
1552    }
1553  } else if (rn.IsLow()) {
1554    switch (type) {
1555      case kCbnz: {
1556        Label done;
1557        cbz(rn, &done);
1558        b(label);
1559        Bind(&done);
1560        return;
1561      }
1562      case kCbz: {
1563        Label done;
1564        cbnz(rn, &done);
1565        b(label);
1566        Bind(&done);
1567        return;
1568      }
1569      default:
1570        break;
1571    }
1572  }
1573  Assembler::Delegate(type, instruction, rn, label);
1574}
1575
1576
1577template <typename T>
1578static inline bool IsI64BitPattern(T imm) {
1579  for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
1580    if (((imm & mask) != mask) && ((imm & mask) != 0)) return false;
1581  }
1582  return true;
1583}
1584
1585
1586template <typename T>
1587static inline bool IsI8BitPattern(T imm) {
1588  uint8_t imm8 = imm & 0xff;
1589  for (unsigned rep = sizeof(T) - 1; rep > 0; rep--) {
1590    imm >>= 8;
1591    if ((imm & 0xff) != imm8) return false;
1592  }
1593  return true;
1594}
1595
1596
1597static inline bool CanBeInverted(uint32_t imm32) {
1598  uint32_t fill8 = 0;
1599
1600  if ((imm32 & 0xffffff00) == 0xffffff00) {
1601    //    11111111 11111111 11111111 abcdefgh
1602    return true;
1603  }
1604  if (((imm32 & 0xff) == 0) || ((imm32 & 0xff) == 0xff)) {
1605    fill8 = imm32 & 0xff;
1606    imm32 >>= 8;
1607    if ((imm32 >> 8) == 0xffff) {
1608      //    11111111 11111111 abcdefgh 00000000
1609      // or 11111111 11111111 abcdefgh 11111111
1610      return true;
1611    }
1612    if ((imm32 & 0xff) == fill8) {
1613      imm32 >>= 8;
1614      if ((imm32 >> 8) == 0xff) {
1615        //    11111111 abcdefgh 00000000 00000000
1616        // or 11111111 abcdefgh 11111111 11111111
1617        return true;
1618      }
1619      if ((fill8 == 0xff) && ((imm32 & 0xff) == 0xff)) {
1620        //    abcdefgh 11111111 11111111 11111111
1621        return true;
1622      }
1623    }
1624  }
1625  return false;
1626}
1627
1628
1629template <typename RES, typename T>
1630static inline RES replicate(T imm) {
1631  VIXL_ASSERT((sizeof(RES) > sizeof(T)) &&
1632              (((sizeof(RES) / sizeof(T)) * sizeof(T)) == sizeof(RES)));
1633  RES res = imm;
1634  for (unsigned i = sizeof(RES) / sizeof(T) - 1; i > 0; i--) {
1635    res = (res << (sizeof(T) * 8)) | imm;
1636  }
1637  return res;
1638}
1639
1640
1641void MacroAssembler::Delegate(InstructionType type,
1642                              InstructionCondDtSSop instruction,
1643                              Condition cond,
1644                              DataType dt,
1645                              SRegister rd,
1646                              const SOperand& operand) {
1647  CONTEXT_SCOPE;
1648  if (type == kVmov) {
1649    if (operand.IsImmediate() && dt.Is(F32)) {
1650      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1651      if (neon_imm.CanConvert<float>()) {
1652        // movw ip, imm16
1653        // movk ip, imm16
1654        // vmov s0, ip
1655        UseScratchRegisterScope temps(this);
1656        Register scratch = temps.Acquire();
1657        float f = neon_imm.GetImmediate<float>();
1658        // TODO: The scope length was measured empirically. We should analyse
1659        // the
1660        // worst-case size and add targetted tests.
1661        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1662        mov(cond, scratch, FloatToRawbits(f));
1663        vmov(cond, rd, scratch);
1664        return;
1665      }
1666    }
1667  }
1668  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1669}
1670
1671
1672void MacroAssembler::Delegate(InstructionType type,
1673                              InstructionCondDtDDop instruction,
1674                              Condition cond,
1675                              DataType dt,
1676                              DRegister rd,
1677                              const DOperand& operand) {
1678  CONTEXT_SCOPE;
1679  if (type == kVmov) {
1680    if (operand.IsImmediate()) {
1681      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1682      switch (dt.GetValue()) {
1683        case I32:
1684          if (neon_imm.CanConvert<uint32_t>()) {
1685            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1686            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1687            if (IsI8BitPattern(imm)) {
1688              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1689              vmov(cond, I8, rd, imm & 0xff);
1690              return;
1691            }
1692            // vmov.i32 d0, 0xff0000ff will translate into
1693            // vmov.i64 d0, 0xff0000ffff0000ff
1694            if (IsI64BitPattern(imm)) {
1695              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1696              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1697              return;
1698            }
1699            // vmov.i32 d0, 0xffab0000 will translate into
1700            // vmvn.i32 d0, 0x0054ffff
1701            if (cond.Is(al) && CanBeInverted(imm)) {
1702              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1703              vmvn(I32, rd, ~imm);
1704              return;
1705            }
1706          }
1707          break;
1708        case I16:
1709          if (neon_imm.CanConvert<uint16_t>()) {
1710            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1711            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1712            if (IsI8BitPattern(imm)) {
1713              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1714              vmov(cond, I8, rd, imm & 0xff);
1715              return;
1716            }
1717          }
1718          break;
1719        case I64:
1720          if (neon_imm.CanConvert<uint64_t>()) {
1721            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1722            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1723            if (IsI8BitPattern(imm)) {
1724              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1725              vmov(cond, I8, rd, imm & 0xff);
1726              return;
1727            }
1728            // mov ip, lo(imm64)
1729            // vdup d0, ip
1730            // vdup is prefered to 'vmov d0[0]' as d0[1] does not need to be
1731            // preserved
1732            {
1733              UseScratchRegisterScope temps(this);
1734              Register scratch = temps.Acquire();
1735              {
1736                // TODO: The scope length was measured empirically. We should
1737                // analyse the
1738                // worst-case size and add targetted tests.
1739                CodeBufferCheckScope scope(this,
1740                                           2 * kMaxInstructionSizeInBytes);
1741                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1742              }
1743              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1744              vdup(cond, Untyped32, rd, scratch);
1745            }
1746            // mov ip, hi(imm64)
1747            // vmov d0[1], ip
1748            {
1749              UseScratchRegisterScope temps(this);
1750              Register scratch = temps.Acquire();
1751              {
1752                // TODO: The scope length was measured empirically. We should
1753                // analyse the
1754                // worst-case size and add targetted tests.
1755                CodeBufferCheckScope scope(this,
1756                                           2 * kMaxInstructionSizeInBytes);
1757                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1758              }
1759              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1760              vmov(cond, Untyped32, DRegisterLane(rd, 1), scratch);
1761            }
1762            return;
1763          }
1764          break;
1765        default:
1766          break;
1767      }
1768      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1769      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1770        // mov ip, imm32
1771        // vdup.16 d0, ip
1772        UseScratchRegisterScope temps(this);
1773        Register scratch = temps.Acquire();
1774        {
1775          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1776          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1777        }
1778        DataTypeValue vdup_dt = Untyped32;
1779        switch (dt.GetValue()) {
1780          case I16:
1781            vdup_dt = Untyped16;
1782            break;
1783          case I32:
1784            vdup_dt = Untyped32;
1785            break;
1786          default:
1787            VIXL_UNREACHABLE();
1788        }
1789        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1790        vdup(cond, vdup_dt, rd, scratch);
1791        return;
1792      }
1793      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1794        float f = neon_imm.GetImmediate<float>();
1795        // Punt to vmov.i32
1796        // TODO: The scope length was guessed based on the double case below. We
1797        // should analyse the worst-case size and add targetted tests.
1798        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1799        vmov(cond, I32, rd, FloatToRawbits(f));
1800        return;
1801      }
1802      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1803        // Punt to vmov.i64
1804        double d = neon_imm.GetImmediate<double>();
1805        // TODO: The scope length was measured empirically. We should analyse
1806        // the
1807        // worst-case size and add targetted tests.
1808        CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1809        vmov(cond, I64, rd, DoubleToRawbits(d));
1810        return;
1811      }
1812    }
1813  }
1814  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1815}
1816
1817
1818void MacroAssembler::Delegate(InstructionType type,
1819                              InstructionCondDtQQop instruction,
1820                              Condition cond,
1821                              DataType dt,
1822                              QRegister rd,
1823                              const QOperand& operand) {
1824  CONTEXT_SCOPE;
1825  if (type == kVmov) {
1826    if (operand.IsImmediate()) {
1827      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1828      switch (dt.GetValue()) {
1829        case I32:
1830          if (neon_imm.CanConvert<uint32_t>()) {
1831            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1832            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1833            if (IsI8BitPattern(imm)) {
1834              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1835              vmov(cond, I8, rd, imm & 0xff);
1836              return;
1837            }
1838            // vmov.i32 d0, 0xff0000ff will translate into
1839            // vmov.i64 d0, 0xff0000ffff0000ff
1840            if (IsI64BitPattern(imm)) {
1841              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1842              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1843              return;
1844            }
1845            // vmov.i32 d0, 0xffab0000 will translate into
1846            // vmvn.i32 d0, 0x0054ffff
1847            if (CanBeInverted(imm)) {
1848              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1849              vmvn(cond, I32, rd, ~imm);
1850              return;
1851            }
1852          }
1853          break;
1854        case I16:
1855          if (neon_imm.CanConvert<uint16_t>()) {
1856            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1857            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1858            if (IsI8BitPattern(imm)) {
1859              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1860              vmov(cond, I8, rd, imm & 0xff);
1861              return;
1862            }
1863          }
1864          break;
1865        case I64:
1866          if (neon_imm.CanConvert<uint64_t>()) {
1867            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1868            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1869            if (IsI8BitPattern(imm)) {
1870              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1871              vmov(cond, I8, rd, imm & 0xff);
1872              return;
1873            }
1874            // mov ip, lo(imm64)
1875            // vdup q0, ip
1876            // vdup is prefered to 'vmov d0[0]' as d0[1-3] don't need to be
1877            // preserved
1878            {
1879              UseScratchRegisterScope temps(this);
1880              Register scratch = temps.Acquire();
1881              {
1882                CodeBufferCheckScope scope(this,
1883                                           2 * kMaxInstructionSizeInBytes);
1884                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1885              }
1886              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1887              vdup(cond, Untyped32, rd, scratch);
1888            }
1889            // mov ip, hi(imm64)
1890            // vmov.i32 d0[1], ip
1891            // vmov d1, d0
1892            {
1893              UseScratchRegisterScope temps(this);
1894              Register scratch = temps.Acquire();
1895              {
1896                CodeBufferCheckScope scope(this,
1897                                           2 * kMaxInstructionSizeInBytes);
1898                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1899              }
1900              {
1901                CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1902                vmov(cond,
1903                     Untyped32,
1904                     DRegisterLane(rd.GetLowDRegister(), 1),
1905                     scratch);
1906              }
1907              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1908              vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1909            }
1910            return;
1911          }
1912          break;
1913        default:
1914          break;
1915      }
1916      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1917      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1918        // mov ip, imm32
1919        // vdup.16 d0, ip
1920        UseScratchRegisterScope temps(this);
1921        Register scratch = temps.Acquire();
1922        {
1923          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1924          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1925        }
1926        DataTypeValue vdup_dt = Untyped32;
1927        switch (dt.GetValue()) {
1928          case I16:
1929            vdup_dt = Untyped16;
1930            break;
1931          case I32:
1932            vdup_dt = Untyped32;
1933            break;
1934          default:
1935            VIXL_UNREACHABLE();
1936        }
1937        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1938        vdup(cond, vdup_dt, rd, scratch);
1939        return;
1940      }
1941      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1942        // Punt to vmov.i64
1943        float f = neon_imm.GetImmediate<float>();
1944        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1945        vmov(cond, I32, rd, FloatToRawbits(f));
1946        return;
1947      }
1948      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1949        // Use vmov to create the double in the low D register, then duplicate
1950        // it into the high D register.
1951        double d = neon_imm.GetImmediate<double>();
1952        CodeBufferCheckScope scope(this, 7 * kMaxInstructionSizeInBytes);
1953        vmov(cond, F64, rd.GetLowDRegister(), d);
1954        vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1955        return;
1956      }
1957    }
1958  }
1959  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1960}
1961
1962
1963void MacroAssembler::Delegate(InstructionType type,
1964                              InstructionCondRL instruction,
1965                              Condition cond,
1966                              Register rt,
1967                              Label* label) {
1968  VIXL_ASSERT((type == kLdrb) || (type == kLdrh) || (type == kLdrsb) ||
1969              (type == kLdrsh));
1970
1971  CONTEXT_SCOPE;
1972
1973  if (label->IsBound()) {
1974    CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1975    UseScratchRegisterScope temps(this);
1976    temps.Include(rt);
1977    Register scratch = temps.Acquire();
1978    uint32_t mask = GetOffsetMask(type, Offset);
1979    switch (type) {
1980      case kLdrb:
1981        ldrb(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1982        return;
1983      case kLdrh:
1984        ldrh(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1985        return;
1986      case kLdrsb:
1987        ldrsb(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1988        return;
1989      case kLdrsh:
1990        ldrsh(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1991        return;
1992      default:
1993        VIXL_UNREACHABLE();
1994    }
1995    return;
1996  }
1997
1998  Assembler::Delegate(type, instruction, cond, rt, label);
1999}
2000
2001
2002void MacroAssembler::Delegate(InstructionType type,
2003                              InstructionCondRRL instruction,
2004                              Condition cond,
2005                              Register rt,
2006                              Register rt2,
2007                              Label* label) {
2008  VIXL_ASSERT(type == kLdrd);
2009
2010  CONTEXT_SCOPE;
2011
2012  if (label->IsBound()) {
2013    CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
2014    UseScratchRegisterScope temps(this);
2015    temps.Include(rt, rt2);
2016    Register scratch = temps.Acquire();
2017    uint32_t mask = GetOffsetMask(type, Offset);
2018    ldrd(rt, rt2, MemOperandComputationHelper(cond, scratch, label, mask));
2019    return;
2020  }
2021
2022  Assembler::Delegate(type, instruction, cond, rt, rt2, label);
2023}
2024
2025
2026void MacroAssembler::Delegate(InstructionType type,
2027                              InstructionCondSizeRMop instruction,
2028                              Condition cond,
2029                              EncodingSize size,
2030                              Register rd,
2031                              const MemOperand& operand) {
2032  // ldr ldrb ldrh ldrsb ldrsh str strb strh
2033  CONTEXT_SCOPE;
2034  VIXL_ASSERT(size.IsBest());
2035  VIXL_ASSERT((type == kLdr) || (type == kLdrb) || (type == kLdrh) ||
2036              (type == kLdrsb) || (type == kLdrsh) || (type == kStr) ||
2037              (type == kStrb) || (type == kStrh));
2038  if (operand.IsImmediate()) {
2039    const Register& rn = operand.GetBaseRegister();
2040    AddrMode addrmode = operand.GetAddrMode();
2041    int32_t offset = operand.GetOffsetImmediate();
2042    uint32_t mask = GetOffsetMask(type, addrmode);
2043    bool negative;
2044    // Try to maximize the offset use by the MemOperand (load_store_offset).
2045    // Add or subtract the part which can't be used by the MemOperand
2046    // (add_sub_offset).
2047    int32_t add_sub_offset;
2048    int32_t load_store_offset;
2049    load_store_offset = offset & mask;
2050    if (offset >= 0) {
2051      negative = false;
2052      add_sub_offset = offset & ~mask;
2053    } else {
2054      negative = true;
2055      add_sub_offset = -offset & ~mask;
2056      if (load_store_offset > 0) add_sub_offset += mask + 1;
2057    }
2058    switch (addrmode) {
2059      case PreIndex:
2060        // Avoid the unpredictable case 'str r0, [r0, imm]!'
2061        if (!rn.Is(rd)) {
2062          // Pre-Indexed case:
2063          // ldr r0, [r1, 12345]! will translate into
2064          //   add r1, r1, 12345
2065          //   ldr r0, [r1]
2066          {
2067            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2068            if (negative) {
2069              sub(cond, rn, rn, add_sub_offset);
2070            } else {
2071              add(cond, rn, rn, add_sub_offset);
2072            }
2073          }
2074          {
2075            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2076            (this->*instruction)(cond,
2077                                 size,
2078                                 rd,
2079                                 MemOperand(rn, load_store_offset, PreIndex));
2080          }
2081          return;
2082        }
2083        break;
2084      case Offset: {
2085        UseScratchRegisterScope temps(this);
2086        // Allow using the destination as a scratch register if possible.
2087        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
2088            !rd.Is(rn)) {
2089          temps.Include(rd);
2090        }
2091        Register scratch = temps.Acquire();
2092        // Offset case:
2093        // ldr r0, [r1, 12345] will translate into
2094        //   add r0, r1, 12345
2095        //   ldr r0, [r0]
2096        {
2097          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2098          if (negative) {
2099            sub(cond, scratch, rn, add_sub_offset);
2100          } else {
2101            add(cond, scratch, rn, add_sub_offset);
2102          }
2103        }
2104        {
2105          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2106          (this->*instruction)(cond,
2107                               size,
2108                               rd,
2109                               MemOperand(scratch, load_store_offset));
2110        }
2111        return;
2112      }
2113      case PostIndex:
2114        // Avoid the unpredictable case 'ldr r0, [r0], imm'
2115        if (!rn.Is(rd)) {
2116          // Post-indexed case:
2117          // ldr r0. [r1], imm32 will translate into
2118          //   ldr r0, [r1]
2119          //   movw ip. imm32 & 0xffffffff
2120          //   movt ip, imm32 >> 16
2121          //   add r1, r1, ip
2122          {
2123            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2124            (this->*instruction)(cond,
2125                                 size,
2126                                 rd,
2127                                 MemOperand(rn, load_store_offset, PostIndex));
2128          }
2129          {
2130            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2131            if (negative) {
2132              sub(cond, rn, rn, add_sub_offset);
2133            } else {
2134              add(cond, rn, rn, add_sub_offset);
2135            }
2136          }
2137          return;
2138        }
2139        break;
2140    }
2141  } else if (operand.IsPlainRegister()) {
2142    const Register& rn = operand.GetBaseRegister();
2143    AddrMode addrmode = operand.GetAddrMode();
2144    const Register& rm = operand.GetOffsetRegister();
2145    if (rm.IsPC()) {
2146      VIXL_ABORT_WITH_MSG(
2147          "The MacroAssembler does not convert loads and stores with a PC "
2148          "offset register.\n");
2149    }
2150    if (rn.IsPC()) {
2151      if (addrmode == Offset) {
2152        if (IsUsingT32()) {
2153          VIXL_ABORT_WITH_MSG(
2154              "The MacroAssembler does not convert loads and stores with a PC "
2155              "base register for T32.\n");
2156        }
2157      } else {
2158        VIXL_ABORT_WITH_MSG(
2159            "The MacroAssembler does not convert loads and stores with a PC "
2160            "base register in pre-index or post-index mode.\n");
2161      }
2162    }
2163    switch (addrmode) {
2164      case PreIndex:
2165        // Avoid the unpredictable case 'str r0, [r0, imm]!'
2166        if (!rn.Is(rd)) {
2167          // Pre-Indexed case:
2168          // ldr r0, [r1, r2]! will translate into
2169          //   add r1, r1, r2
2170          //   ldr r0, [r1]
2171          {
2172            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2173            if (operand.GetSign().IsPlus()) {
2174              add(cond, rn, rn, rm);
2175            } else {
2176              sub(cond, rn, rn, rm);
2177            }
2178          }
2179          {
2180            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2181            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
2182          }
2183          return;
2184        }
2185        break;
2186      case Offset: {
2187        UseScratchRegisterScope temps(this);
2188        // Allow using the destination as a scratch register if this is not a
2189        // store.
2190        // Avoid using PC as a temporary as this has side-effects.
2191        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
2192            !rd.IsPC()) {
2193          temps.Include(rd);
2194        }
2195        Register scratch = temps.Acquire();
2196        // Offset case:
2197        // ldr r0, [r1, r2] will translate into
2198        //   add r0, r1, r2
2199        //   ldr r0, [r0]
2200        {
2201          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2202          if (operand.GetSign().IsPlus()) {
2203            add(cond, scratch, rn, rm);
2204          } else {
2205            sub(cond, scratch, rn, rm);
2206          }
2207        }
2208        {
2209          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2210          (this->*instruction)(cond, size, rd, MemOperand(scratch, Offset));
2211        }
2212        return;
2213      }
2214      case PostIndex:
2215        // Avoid the unpredictable case 'ldr r0, [r0], imm'
2216        if (!rn.Is(rd)) {
2217          // Post-indexed case:
2218          // ldr r0. [r1], r2 will translate into
2219          //   ldr r0, [r1]
2220          //   add r1, r1, r2
2221          {
2222            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2223            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
2224          }
2225          {
2226            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2227            if (operand.GetSign().IsPlus()) {
2228              add(cond, rn, rn, rm);
2229            } else {
2230              sub(cond, rn, rn, rm);
2231            }
2232          }
2233          return;
2234        }
2235        break;
2236    }
2237  }
2238  Assembler::Delegate(type, instruction, cond, size, rd, operand);
2239}
2240
2241
2242void MacroAssembler::Delegate(InstructionType type,
2243                              InstructionCondRRMop instruction,
2244                              Condition cond,
2245                              Register rt,
2246                              Register rt2,
2247                              const MemOperand& operand) {
2248  // ldaexd, ldrd, ldrexd, stlex, stlexb, stlexh, strd, strex, strexb, strexh
2249
2250  if ((type == kLdaexd) || (type == kLdrexd) || (type == kStlex) ||
2251      (type == kStlexb) || (type == kStlexh) || (type == kStrex) ||
2252      (type == kStrexb) || (type == kStrexh)) {
2253    UnimplementedDelegate(type);
2254    return;
2255  }
2256
2257  VIXL_ASSERT((type == kLdrd) || (type == kStrd));
2258
2259  CONTEXT_SCOPE;
2260
2261  // TODO: Should we allow these cases?
2262  if (IsUsingA32()) {
2263    // The first register needs to be even.
2264    if ((rt.GetCode() & 1) != 0) {
2265      UnimplementedDelegate(type);
2266      return;
2267    }
2268    // Registers need to be adjacent.
2269    if (((rt.GetCode() + 1) % kNumberOfRegisters) != rt2.GetCode()) {
2270      UnimplementedDelegate(type);
2271      return;
2272    }
2273    // LDRD lr, pc [...] is not allowed.
2274    if (rt.Is(lr)) {
2275      UnimplementedDelegate(type);
2276      return;
2277    }
2278  }
2279
2280  if (operand.IsImmediate()) {
2281    const Register& rn = operand.GetBaseRegister();
2282    AddrMode addrmode = operand.GetAddrMode();
2283    int32_t offset = operand.GetOffsetImmediate();
2284    switch (addrmode) {
2285      case PreIndex: {
2286        // Allow using the destinations as a scratch registers if possible.
2287        UseScratchRegisterScope temps(this);
2288        if (type == kLdrd) {
2289          if (!rt.Is(rn)) temps.Include(rt);
2290          if (!rt2.Is(rn)) temps.Include(rt2);
2291        }
2292
2293        // Pre-Indexed case:
2294        // ldrd r0, r1, [r2, 12345]! will translate into
2295        //   add r2, 12345
2296        //   ldrd r0, r1, [r2]
2297        {
2298          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2299          add(cond, rn, rn, offset);
2300        }
2301        {
2302          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2303          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2304        }
2305        return;
2306      }
2307      case Offset: {
2308        UseScratchRegisterScope temps(this);
2309        // Allow using the destinations as a scratch registers if possible.
2310        if (type == kLdrd) {
2311          if (!rt.Is(rn)) temps.Include(rt);
2312          if (!rt2.Is(rn)) temps.Include(rt2);
2313        }
2314        Register scratch = temps.Acquire();
2315        // Offset case:
2316        // ldrd r0, r1, [r2, 12345] will translate into
2317        //   add r0, r2, 12345
2318        //   ldrd r0, r1, [r0]
2319        {
2320          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2321          add(cond, scratch, rn, offset);
2322        }
2323        {
2324          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2325          (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
2326        }
2327        return;
2328      }
2329      case PostIndex:
2330        // Avoid the unpredictable case 'ldrd r0, r1, [r0], imm'
2331        if (!rn.Is(rt) && !rn.Is(rt2)) {
2332          // Post-indexed case:
2333          // ldrd r0, r1, [r2], imm32 will translate into
2334          //   ldrd r0, r1, [r2]
2335          //   movw ip. imm32 & 0xffffffff
2336          //   movt ip, imm32 >> 16
2337          //   add r2, ip
2338          {
2339            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2340            (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2341          }
2342          {
2343            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2344            add(cond, rn, rn, offset);
2345          }
2346          return;
2347        }
2348        break;
2349    }
2350  }
2351  if (operand.IsPlainRegister()) {
2352    const Register& rn = operand.GetBaseRegister();
2353    const Register& rm = operand.GetOffsetRegister();
2354    AddrMode addrmode = operand.GetAddrMode();
2355    switch (addrmode) {
2356      case PreIndex:
2357        // ldrd r0, r1, [r2, r3]! will translate into
2358        //   add r2, r3
2359        //   ldrd r0, r1, [r2]
2360        {
2361          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2362          if (operand.GetSign().IsPlus()) {
2363            add(cond, rn, rn, rm);
2364          } else {
2365            sub(cond, rn, rn, rm);
2366          }
2367        }
2368        {
2369          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2370          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2371        }
2372        return;
2373      case PostIndex:
2374        // ldrd r0, r1, [r2], r3 will translate into
2375        //   ldrd r0, r1, [r2]
2376        //   add r2, r3
2377        {
2378          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2379          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2380        }
2381        {
2382          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2383          if (operand.GetSign().IsPlus()) {
2384            add(cond, rn, rn, rm);
2385          } else {
2386            sub(cond, rn, rn, rm);
2387          }
2388        }
2389        return;
2390      case Offset: {
2391        UseScratchRegisterScope temps(this);
2392        // Allow using the destinations as a scratch registers if possible.
2393        if (type == kLdrd) {
2394          if (!rt.Is(rn)) temps.Include(rt);
2395          if (!rt2.Is(rn)) temps.Include(rt2);
2396        }
2397        Register scratch = temps.Acquire();
2398        // Offset case:
2399        // ldrd r0, r1, [r2, r3] will translate into
2400        //   add r0, r2, r3
2401        //   ldrd r0, r1, [r0]
2402        {
2403          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2404          if (operand.GetSign().IsPlus()) {
2405            add(cond, scratch, rn, rm);
2406          } else {
2407            sub(cond, scratch, rn, rm);
2408          }
2409        }
2410        {
2411          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2412          (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
2413        }
2414        return;
2415      }
2416    }
2417  }
2418  Assembler::Delegate(type, instruction, cond, rt, rt2, operand);
2419}
2420
2421
2422void MacroAssembler::Delegate(InstructionType type,
2423                              InstructionCondDtSMop instruction,
2424                              Condition cond,
2425                              DataType dt,
2426                              SRegister rd,
2427                              const MemOperand& operand) {
2428  // vldr.32 vstr.32
2429  CONTEXT_SCOPE;
2430  if (operand.IsImmediate()) {
2431    const Register& rn = operand.GetBaseRegister();
2432    AddrMode addrmode = operand.GetAddrMode();
2433    int32_t offset = operand.GetOffsetImmediate();
2434    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2435                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2436    if (rn.IsPC()) {
2437      VIXL_ABORT_WITH_MSG(
2438          "The MacroAssembler does not convert vldr or vstr with a PC base "
2439          "register.\n");
2440    }
2441    switch (addrmode) {
2442      case PreIndex:
2443        // Pre-Indexed case:
2444        // vldr.32 s0, [r1, 12345]! will translate into
2445        //   add r1, 12345
2446        //   vldr.32 s0, [r1]
2447        if (offset != 0) {
2448          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2449          add(cond, rn, rn, offset);
2450        }
2451        {
2452          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2453          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2454        }
2455        return;
2456      case Offset: {
2457        UseScratchRegisterScope temps(this);
2458        Register scratch = temps.Acquire();
2459        // Offset case:
2460        // vldr.32 s0, [r1, 12345] will translate into
2461        //   add ip, r1, 12345
2462        //   vldr.32 s0, [ip]
2463        {
2464          VIXL_ASSERT(offset != 0);
2465          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2466          add(cond, scratch, rn, offset);
2467        }
2468        {
2469          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2470          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2471        }
2472        return;
2473      }
2474      case PostIndex:
2475        // Post-indexed case:
2476        // vldr.32 s0, [r1], imm32 will translate into
2477        //   vldr.32 s0, [r1]
2478        //   movw ip. imm32 & 0xffffffff
2479        //   movt ip, imm32 >> 16
2480        //   add r1, ip
2481        {
2482          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2483          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2484        }
2485        if (offset != 0) {
2486          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2487          add(cond, rn, rn, offset);
2488        }
2489        return;
2490    }
2491  }
2492  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2493}
2494
2495
2496void MacroAssembler::Delegate(InstructionType type,
2497                              InstructionCondDtDMop instruction,
2498                              Condition cond,
2499                              DataType dt,
2500                              DRegister rd,
2501                              const MemOperand& operand) {
2502  // vldr.64 vstr.64
2503  CONTEXT_SCOPE;
2504  if (operand.IsImmediate()) {
2505    const Register& rn = operand.GetBaseRegister();
2506    AddrMode addrmode = operand.GetAddrMode();
2507    int32_t offset = operand.GetOffsetImmediate();
2508    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2509                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2510    if (rn.IsPC()) {
2511      VIXL_ABORT_WITH_MSG(
2512          "The MacroAssembler does not convert vldr or vstr with a PC base "
2513          "register.\n");
2514    }
2515    switch (addrmode) {
2516      case PreIndex:
2517        // Pre-Indexed case:
2518        // vldr.64 d0, [r1, 12345]! will translate into
2519        //   add r1, 12345
2520        //   vldr.64 d0, [r1]
2521        if (offset != 0) {
2522          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2523          add(cond, rn, rn, offset);
2524        }
2525        {
2526          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2527          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2528        }
2529        return;
2530      case Offset: {
2531        UseScratchRegisterScope temps(this);
2532        Register scratch = temps.Acquire();
2533        // Offset case:
2534        // vldr.64 d0, [r1, 12345] will translate into
2535        //   add ip, r1, 12345
2536        //   vldr.32 s0, [ip]
2537        {
2538          VIXL_ASSERT(offset != 0);
2539          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2540          add(cond, scratch, rn, offset);
2541        }
2542        {
2543          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2544          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2545        }
2546        return;
2547      }
2548      case PostIndex:
2549        // Post-indexed case:
2550        // vldr.64 d0. [r1], imm32 will translate into
2551        //   vldr.64 d0, [r1]
2552        //   movw ip. imm32 & 0xffffffff
2553        //   movt ip, imm32 >> 16
2554        //   add r1, ip
2555        {
2556          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2557          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2558        }
2559        if (offset != 0) {
2560          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2561          add(cond, rn, rn, offset);
2562        }
2563        return;
2564    }
2565  }
2566  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2567}
2568
2569
2570void MacroAssembler::Delegate(InstructionType type,
2571                              InstructionCondMsrOp instruction,
2572                              Condition cond,
2573                              MaskedSpecialRegister spec_reg,
2574                              const Operand& operand) {
2575  USE(type);
2576  VIXL_ASSERT(type == kMsr);
2577  if (operand.IsImmediate()) {
2578    UseScratchRegisterScope temps(this);
2579    Register scratch = temps.Acquire();
2580    {
2581      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
2582      mov(cond, scratch, operand);
2583    }
2584    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2585    msr(cond, spec_reg, scratch);
2586    return;
2587  }
2588  Assembler::Delegate(type, instruction, cond, spec_reg, operand);
2589}
2590
2591
2592void MacroAssembler::Delegate(InstructionType type,
2593                              InstructionCondDtDL instruction,
2594                              Condition cond,
2595                              DataType dt,
2596                              DRegister rd,
2597                              Label* label) {
2598  VIXL_ASSERT(type == kVldr);
2599
2600  CONTEXT_SCOPE;
2601
2602  if (label->IsBound()) {
2603    CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
2604    UseScratchRegisterScope temps(this);
2605    Register scratch = temps.Acquire();
2606    uint32_t mask = GetOffsetMask(type, Offset);
2607    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, label, mask));
2608    return;
2609  }
2610
2611  Assembler::Delegate(type, instruction, cond, dt, rd, label);
2612}
2613
2614
2615void MacroAssembler::Delegate(InstructionType type,
2616                              InstructionCondDtSL instruction,
2617                              Condition cond,
2618                              DataType dt,
2619                              SRegister rd,
2620                              Label* label) {
2621  VIXL_ASSERT(type == kVldr);
2622
2623  CONTEXT_SCOPE;
2624
2625  if (label->IsBound()) {
2626    CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
2627    UseScratchRegisterScope temps(this);
2628    Register scratch = temps.Acquire();
2629    uint32_t mask = GetOffsetMask(type, Offset);
2630    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, label, mask));
2631    return;
2632  }
2633
2634  Assembler::Delegate(type, instruction, cond, dt, rd, label);
2635}
2636
2637
2638#undef CONTEXT_SCOPE
2639#undef TOSTRING
2640#undef STRINGIFY
2641
2642// Start of generated code.
2643// End of generated code.
2644}  // namespace aarch32
2645}  // namespace vixl
2646