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