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