Home | History | Annotate | Download | only in aarch32
      1 // Copyright 2017, 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 
     36 namespace vixl {
     37 namespace aarch32 {
     38 
     39 ExactAssemblyScopeWithoutPoolsCheck::ExactAssemblyScopeWithoutPoolsCheck(
     40     MacroAssembler* masm, size_t size, SizePolicy size_policy)
     41     : ExactAssemblyScope(masm,
     42                          size,
     43                          size_policy,
     44                          ExactAssemblyScope::kIgnorePools) {}
     45 
     46 void UseScratchRegisterScope::Open(MacroAssembler* masm) {
     47   VIXL_ASSERT(masm_ == NULL);
     48   VIXL_ASSERT(masm != NULL);
     49   masm_ = masm;
     50 
     51   old_available_ = masm_->GetScratchRegisterList()->GetList();
     52   old_available_vfp_ = masm_->GetScratchVRegisterList()->GetList();
     53 
     54   parent_ = masm->GetCurrentScratchRegisterScope();
     55   masm->SetCurrentScratchRegisterScope(this);
     56 }
     57 
     58 
     59 void UseScratchRegisterScope::Close() {
     60   if (masm_ != NULL) {
     61     // Ensure that scopes nest perfectly, and do not outlive their parents.
     62     // This is a run-time check because the order of destruction of objects in
     63     // the _same_ scope is implementation-defined, and is likely to change in
     64     // optimised builds.
     65     VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
     66     masm_->SetCurrentScratchRegisterScope(parent_);
     67 
     68     masm_->GetScratchRegisterList()->SetList(old_available_);
     69     masm_->GetScratchVRegisterList()->SetList(old_available_vfp_);
     70 
     71     masm_ = NULL;
     72   }
     73 }
     74 
     75 
     76 bool UseScratchRegisterScope::IsAvailable(const Register& reg) const {
     77   VIXL_ASSERT(masm_ != NULL);
     78   VIXL_ASSERT(reg.IsValid());
     79   return masm_->GetScratchRegisterList()->Includes(reg);
     80 }
     81 
     82 
     83 bool UseScratchRegisterScope::IsAvailable(const VRegister& reg) const {
     84   VIXL_ASSERT(masm_ != NULL);
     85   VIXL_ASSERT(reg.IsValid());
     86   return masm_->GetScratchVRegisterList()->IncludesAllOf(reg);
     87 }
     88 
     89 
     90 Register UseScratchRegisterScope::Acquire() {
     91   VIXL_ASSERT(masm_ != NULL);
     92   Register reg = masm_->GetScratchRegisterList()->GetFirstAvailableRegister();
     93   VIXL_CHECK(reg.IsValid());
     94   masm_->GetScratchRegisterList()->Remove(reg);
     95   return reg;
     96 }
     97 
     98 
     99 VRegister UseScratchRegisterScope::AcquireV(unsigned size_in_bits) {
    100   switch (size_in_bits) {
    101     case kSRegSizeInBits:
    102       return AcquireS();
    103     case kDRegSizeInBits:
    104       return AcquireD();
    105     case kQRegSizeInBits:
    106       return AcquireQ();
    107     default:
    108       VIXL_UNREACHABLE();
    109       return NoVReg;
    110   }
    111 }
    112 
    113 
    114 QRegister UseScratchRegisterScope::AcquireQ() {
    115   VIXL_ASSERT(masm_ != NULL);
    116   QRegister reg =
    117       masm_->GetScratchVRegisterList()->GetFirstAvailableQRegister();
    118   VIXL_CHECK(reg.IsValid());
    119   masm_->GetScratchVRegisterList()->Remove(reg);
    120   return reg;
    121 }
    122 
    123 
    124 DRegister UseScratchRegisterScope::AcquireD() {
    125   VIXL_ASSERT(masm_ != NULL);
    126   DRegister reg =
    127       masm_->GetScratchVRegisterList()->GetFirstAvailableDRegister();
    128   VIXL_CHECK(reg.IsValid());
    129   masm_->GetScratchVRegisterList()->Remove(reg);
    130   return reg;
    131 }
    132 
    133 
    134 SRegister UseScratchRegisterScope::AcquireS() {
    135   VIXL_ASSERT(masm_ != NULL);
    136   SRegister reg =
    137       masm_->GetScratchVRegisterList()->GetFirstAvailableSRegister();
    138   VIXL_CHECK(reg.IsValid());
    139   masm_->GetScratchVRegisterList()->Remove(reg);
    140   return reg;
    141 }
    142 
    143 
    144 void UseScratchRegisterScope::Release(const Register& reg) {
    145   VIXL_ASSERT(masm_ != NULL);
    146   VIXL_ASSERT(reg.IsValid());
    147   VIXL_ASSERT(!masm_->GetScratchRegisterList()->Includes(reg));
    148   masm_->GetScratchRegisterList()->Combine(reg);
    149 }
    150 
    151 
    152 void UseScratchRegisterScope::Release(const VRegister& reg) {
    153   VIXL_ASSERT(masm_ != NULL);
    154   VIXL_ASSERT(reg.IsValid());
    155   VIXL_ASSERT(!masm_->GetScratchVRegisterList()->IncludesAliasOf(reg));
    156   masm_->GetScratchVRegisterList()->Combine(reg);
    157 }
    158 
    159 
    160 void UseScratchRegisterScope::Include(const RegisterList& list) {
    161   VIXL_ASSERT(masm_ != NULL);
    162   RegisterList excluded_registers(sp, lr, pc);
    163   uint32_t mask = list.GetList() & ~excluded_registers.GetList();
    164   RegisterList* available = masm_->GetScratchRegisterList();
    165   available->SetList(available->GetList() | mask);
    166 }
    167 
    168 
    169 void UseScratchRegisterScope::Include(const VRegisterList& list) {
    170   VIXL_ASSERT(masm_ != NULL);
    171   VRegisterList* available = masm_->GetScratchVRegisterList();
    172   available->SetList(available->GetList() | list.GetList());
    173 }
    174 
    175 
    176 void UseScratchRegisterScope::Exclude(const RegisterList& list) {
    177   VIXL_ASSERT(masm_ != NULL);
    178   RegisterList* available = masm_->GetScratchRegisterList();
    179   available->SetList(available->GetList() & ~list.GetList());
    180 }
    181 
    182 
    183 void UseScratchRegisterScope::Exclude(const VRegisterList& list) {
    184   VIXL_ASSERT(masm_ != NULL);
    185   VRegisterList* available = masm_->GetScratchVRegisterList();
    186   available->SetList(available->GetList() & ~list.GetList());
    187 }
    188 
    189 
    190 void UseScratchRegisterScope::Exclude(const Operand& operand) {
    191   if (operand.IsImmediateShiftedRegister()) {
    192     Exclude(operand.GetBaseRegister());
    193   } else if (operand.IsRegisterShiftedRegister()) {
    194     Exclude(operand.GetBaseRegister(), operand.GetShiftRegister());
    195   } else {
    196     VIXL_ASSERT(operand.IsImmediate());
    197   }
    198 }
    199 
    200 
    201 void UseScratchRegisterScope::ExcludeAll() {
    202   VIXL_ASSERT(masm_ != NULL);
    203   masm_->GetScratchRegisterList()->SetList(0);
    204   masm_->GetScratchVRegisterList()->SetList(0);
    205 }
    206 
    207 
    208 void MacroAssembler::EnsureEmitPoolsFor(size_t size_arg) {
    209   // We skip the check when the pools are blocked.
    210   if (ArePoolsBlocked()) return;
    211 
    212   VIXL_ASSERT(IsUint32(size_arg));
    213   uint32_t size = static_cast<uint32_t>(size_arg);
    214 
    215   if (pool_manager_.MustEmit(GetCursorOffset(), size)) {
    216     int32_t new_pc = pool_manager_.Emit(this, GetCursorOffset(), size);
    217     VIXL_ASSERT(new_pc == GetCursorOffset());
    218     USE(new_pc);
    219   }
    220 }
    221 
    222 
    223 void MacroAssembler::HandleOutOfBoundsImmediate(Condition cond,
    224                                                 Register tmp,
    225                                                 uint32_t imm) {
    226   if (IsUintN(16, imm)) {
    227     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    228     mov(cond, tmp, imm & 0xffff);
    229     return;
    230   }
    231   if (IsUsingT32()) {
    232     if (ImmediateT32::IsImmediateT32(~imm)) {
    233       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    234       mvn(cond, tmp, ~imm);
    235       return;
    236     }
    237   } else {
    238     if (ImmediateA32::IsImmediateA32(~imm)) {
    239       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    240       mvn(cond, tmp, ~imm);
    241       return;
    242     }
    243   }
    244   CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
    245   mov(cond, tmp, imm & 0xffff);
    246   movt(cond, tmp, imm >> 16);
    247 }
    248 
    249 
    250 MemOperand MacroAssembler::MemOperandComputationHelper(
    251     Condition cond,
    252     Register scratch,
    253     Register base,
    254     uint32_t offset,
    255     uint32_t extra_offset_mask) {
    256   VIXL_ASSERT(!AliasesAvailableScratchRegister(scratch));
    257   VIXL_ASSERT(!AliasesAvailableScratchRegister(base));
    258   VIXL_ASSERT(allow_macro_instructions_);
    259   VIXL_ASSERT(OutsideITBlock());
    260 
    261   // Check for the simple pass-through case.
    262   if ((offset & extra_offset_mask) == offset) return MemOperand(base, offset);
    263 
    264   MacroEmissionCheckScope guard(this);
    265   ITScope it_scope(this, &cond, guard);
    266 
    267   uint32_t load_store_offset = offset & extra_offset_mask;
    268   uint32_t add_offset = offset & ~extra_offset_mask;
    269   if ((add_offset != 0) &&
    270       (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
    271     load_store_offset = 0;
    272     add_offset = offset;
    273   }
    274 
    275   if (base.IsPC()) {
    276     // Special handling for PC bases. We must read the PC in the first
    277     // instruction (and only in that instruction), and we must also take care to
    278     // keep the same address calculation as loads and stores. For T32, that
    279     // means using something like ADR, which uses AlignDown(PC, 4).
    280 
    281     // We don't handle positive offsets from PC because the intention is not
    282     // clear; does the user expect the offset from the current
    283     // GetCursorOffset(), or to allow a certain amount of space after the
    284     // instruction?
    285     VIXL_ASSERT((offset & 0x80000000) != 0);
    286     if (IsUsingT32()) {
    287       // T32: make the first instruction "SUB (immediate, from PC)" -- an alias
    288       // of ADR -- to get behaviour like loads and stores. This ADR can handle
    289       // at least as much offset as the load_store_offset so it can replace it.
    290 
    291       uint32_t sub_pc_offset = (-offset) & 0xfff;
    292       load_store_offset = (offset + sub_pc_offset) & extra_offset_mask;
    293       add_offset = (offset + sub_pc_offset) & ~extra_offset_mask;
    294 
    295       ExactAssemblyScope scope(this, k32BitT32InstructionSizeInBytes);
    296       sub(cond, scratch, base, sub_pc_offset);
    297 
    298       if (add_offset == 0) return MemOperand(scratch, load_store_offset);
    299 
    300       // The rest of the offset can be generated in the usual way.
    301       base = scratch;
    302     }
    303     // A32 can use any SUB instruction, so we don't have to do anything special
    304     // here except to ensure that we read the PC first.
    305   }
    306 
    307   add(cond, scratch, base, add_offset);
    308   return MemOperand(scratch, load_store_offset);
    309 }
    310 
    311 
    312 uint32_t MacroAssembler::GetOffsetMask(InstructionType type,
    313                                        AddrMode addrmode) {
    314   switch (type) {
    315     case kLdr:
    316     case kLdrb:
    317     case kStr:
    318     case kStrb:
    319       if (IsUsingA32() || (addrmode == Offset)) {
    320         return 0xfff;
    321       } else {
    322         return 0xff;
    323       }
    324     case kLdrsb:
    325     case kLdrh:
    326     case kLdrsh:
    327     case kStrh:
    328       if (IsUsingT32() && (addrmode == Offset)) {
    329         return 0xfff;
    330       } else {
    331         return 0xff;
    332       }
    333     case kVldr:
    334     case kVstr:
    335       return 0x3fc;
    336     case kLdrd:
    337     case kStrd:
    338       if (IsUsingA32()) {
    339         return 0xff;
    340       } else {
    341         return 0x3fc;
    342       }
    343     default:
    344       VIXL_UNREACHABLE();
    345       return 0;
    346   }
    347 }
    348 
    349 
    350 HARDFLOAT void PrintfTrampolineRRRR(
    351     const char* format, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
    352   printf(format, a, b, c, d);
    353 }
    354 
    355 
    356 HARDFLOAT void PrintfTrampolineRRRD(
    357     const char* format, uint32_t a, uint32_t b, uint32_t c, double d) {
    358   printf(format, a, b, c, d);
    359 }
    360 
    361 
    362 HARDFLOAT void PrintfTrampolineRRDR(
    363     const char* format, uint32_t a, uint32_t b, double c, uint32_t d) {
    364   printf(format, a, b, c, d);
    365 }
    366 
    367 
    368 HARDFLOAT void PrintfTrampolineRRDD(
    369     const char* format, uint32_t a, uint32_t b, double c, double d) {
    370   printf(format, a, b, c, d);
    371 }
    372 
    373 
    374 HARDFLOAT void PrintfTrampolineRDRR(
    375     const char* format, uint32_t a, double b, uint32_t c, uint32_t d) {
    376   printf(format, a, b, c, d);
    377 }
    378 
    379 
    380 HARDFLOAT void PrintfTrampolineRDRD(
    381     const char* format, uint32_t a, double b, uint32_t c, double d) {
    382   printf(format, a, b, c, d);
    383 }
    384 
    385 
    386 HARDFLOAT void PrintfTrampolineRDDR(
    387     const char* format, uint32_t a, double b, double c, uint32_t d) {
    388   printf(format, a, b, c, d);
    389 }
    390 
    391 
    392 HARDFLOAT void PrintfTrampolineRDDD(
    393     const char* format, uint32_t a, double b, double c, double d) {
    394   printf(format, a, b, c, d);
    395 }
    396 
    397 
    398 HARDFLOAT void PrintfTrampolineDRRR(
    399     const char* format, double a, uint32_t b, uint32_t c, uint32_t d) {
    400   printf(format, a, b, c, d);
    401 }
    402 
    403 
    404 HARDFLOAT void PrintfTrampolineDRRD(
    405     const char* format, double a, uint32_t b, uint32_t c, double d) {
    406   printf(format, a, b, c, d);
    407 }
    408 
    409 
    410 HARDFLOAT void PrintfTrampolineDRDR(
    411     const char* format, double a, uint32_t b, double c, uint32_t d) {
    412   printf(format, a, b, c, d);
    413 }
    414 
    415 
    416 HARDFLOAT void PrintfTrampolineDRDD(
    417     const char* format, double a, uint32_t b, double c, double d) {
    418   printf(format, a, b, c, d);
    419 }
    420 
    421 
    422 HARDFLOAT void PrintfTrampolineDDRR(
    423     const char* format, double a, double b, uint32_t c, uint32_t d) {
    424   printf(format, a, b, c, d);
    425 }
    426 
    427 
    428 HARDFLOAT void PrintfTrampolineDDRD(
    429     const char* format, double a, double b, uint32_t c, double d) {
    430   printf(format, a, b, c, d);
    431 }
    432 
    433 
    434 HARDFLOAT void PrintfTrampolineDDDR(
    435     const char* format, double a, double b, double c, uint32_t d) {
    436   printf(format, a, b, c, d);
    437 }
    438 
    439 
    440 HARDFLOAT void PrintfTrampolineDDDD(
    441     const char* format, double a, double b, double c, double d) {
    442   printf(format, a, b, c, d);
    443 }
    444 
    445 
    446 void MacroAssembler::Printf(const char* format,
    447                             CPURegister reg1,
    448                             CPURegister reg2,
    449                             CPURegister reg3,
    450                             CPURegister reg4) {
    451   // Exclude all registers from the available scratch registers, so
    452   // that we are able to use ip below.
    453   // TODO: Refactor this function to use UseScratchRegisterScope
    454   // for temporary registers below.
    455   UseScratchRegisterScope scratch(this);
    456   scratch.ExcludeAll();
    457   if (generate_simulator_code_) {
    458     PushRegister(reg4);
    459     PushRegister(reg3);
    460     PushRegister(reg2);
    461     PushRegister(reg1);
    462     Push(RegisterList(r0, r1));
    463     StringLiteral* format_literal =
    464         new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
    465     Adr(r0, format_literal);
    466     uint32_t args = (reg4.GetType() << 12) | (reg3.GetType() << 8) |
    467                     (reg2.GetType() << 4) | reg1.GetType();
    468     Mov(r1, args);
    469     Hvc(kPrintfCode);
    470     Pop(RegisterList(r0, r1));
    471     int size = reg4.GetRegSizeInBytes() + reg3.GetRegSizeInBytes() +
    472                reg2.GetRegSizeInBytes() + reg1.GetRegSizeInBytes();
    473     Drop(size);
    474   } else {
    475     // Generate on a native platform => 32 bit environment.
    476     // Preserve core registers r0-r3, r12, r14
    477     const uint32_t saved_registers_mask =
    478         kCallerSavedRegistersMask | (1 << r5.GetCode());
    479     Push(RegisterList(saved_registers_mask));
    480     // Push VFP registers.
    481     Vpush(Untyped64, DRegisterList(d0, 8));
    482     if (Has32DRegs()) Vpush(Untyped64, DRegisterList(d16, 16));
    483     // Search one register which has been saved and which doesn't need to be
    484     // printed.
    485     RegisterList available_registers(kCallerSavedRegistersMask);
    486     if (reg1.GetType() == CPURegister::kRRegister) {
    487       available_registers.Remove(Register(reg1.GetCode()));
    488     }
    489     if (reg2.GetType() == CPURegister::kRRegister) {
    490       available_registers.Remove(Register(reg2.GetCode()));
    491     }
    492     if (reg3.GetType() == CPURegister::kRRegister) {
    493       available_registers.Remove(Register(reg3.GetCode()));
    494     }
    495     if (reg4.GetType() == CPURegister::kRRegister) {
    496       available_registers.Remove(Register(reg4.GetCode()));
    497     }
    498     Register tmp = available_registers.GetFirstAvailableRegister();
    499     VIXL_ASSERT(tmp.GetType() == CPURegister::kRRegister);
    500     // Push the flags.
    501     Mrs(tmp, APSR);
    502     Push(tmp);
    503     Vmrs(RegisterOrAPSR_nzcv(tmp.GetCode()), FPSCR);
    504     Push(tmp);
    505     // Push the registers to print on the stack.
    506     PushRegister(reg4);
    507     PushRegister(reg3);
    508     PushRegister(reg2);
    509     PushRegister(reg1);
    510     int core_count = 1;
    511     int vfp_count = 0;
    512     uint32_t printf_type = 0;
    513     // Pop the registers to print and store them into r1-r3 and/or d0-d3.
    514     // Reg4 may stay into the stack if all the register to print are core
    515     // registers.
    516     PreparePrintfArgument(reg1, &core_count, &vfp_count, &printf_type);
    517     PreparePrintfArgument(reg2, &core_count, &vfp_count, &printf_type);
    518     PreparePrintfArgument(reg3, &core_count, &vfp_count, &printf_type);
    519     PreparePrintfArgument(reg4, &core_count, &vfp_count, &printf_type);
    520     // Ensure that the stack is aligned on 8 bytes.
    521     And(r5, sp, 0x7);
    522     if (core_count == 5) {
    523       // One 32 bit argument (reg4) has been left on the stack =>  align the
    524       // stack
    525       // before the argument.
    526       Pop(r0);
    527       Sub(sp, sp, r5);
    528       Push(r0);
    529     } else {
    530       Sub(sp, sp, r5);
    531     }
    532     // Select the right trampoline depending on the arguments.
    533     uintptr_t address;
    534     switch (printf_type) {
    535       case 0:
    536         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
    537         break;
    538       case 1:
    539         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRR);
    540         break;
    541       case 2:
    542         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRR);
    543         break;
    544       case 3:
    545         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRR);
    546         break;
    547       case 4:
    548         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDR);
    549         break;
    550       case 5:
    551         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDR);
    552         break;
    553       case 6:
    554         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDR);
    555         break;
    556       case 7:
    557         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDR);
    558         break;
    559       case 8:
    560         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRD);
    561         break;
    562       case 9:
    563         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRD);
    564         break;
    565       case 10:
    566         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRD);
    567         break;
    568       case 11:
    569         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRD);
    570         break;
    571       case 12:
    572         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDD);
    573         break;
    574       case 13:
    575         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDD);
    576         break;
    577       case 14:
    578         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDD);
    579         break;
    580       case 15:
    581         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDD);
    582         break;
    583       default:
    584         VIXL_UNREACHABLE();
    585         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
    586         break;
    587     }
    588     StringLiteral* format_literal =
    589         new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
    590     Adr(r0, format_literal);
    591     Mov(ip, Operand::From(address));
    592     Blx(ip);
    593     // If register reg4 was left on the stack => skip it.
    594     if (core_count == 5) Drop(kRegSizeInBytes);
    595     // Restore the stack as it was before alignment.
    596     Add(sp, sp, r5);
    597     // Restore the flags.
    598     Pop(tmp);
    599     Vmsr(FPSCR, tmp);
    600     Pop(tmp);
    601     Msr(APSR_nzcvqg, tmp);
    602     // Restore the regsisters.
    603     if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
    604     Vpop(Untyped64, DRegisterList(d0, 8));
    605     Pop(RegisterList(saved_registers_mask));
    606   }
    607 }
    608 
    609 
    610 void MacroAssembler::PushRegister(CPURegister reg) {
    611   switch (reg.GetType()) {
    612     case CPURegister::kNoRegister:
    613       break;
    614     case CPURegister::kRRegister:
    615       Push(Register(reg.GetCode()));
    616       break;
    617     case CPURegister::kSRegister:
    618       Vpush(Untyped32, SRegisterList(SRegister(reg.GetCode())));
    619       break;
    620     case CPURegister::kDRegister:
    621       Vpush(Untyped64, DRegisterList(DRegister(reg.GetCode())));
    622       break;
    623     case CPURegister::kQRegister:
    624       VIXL_UNIMPLEMENTED();
    625       break;
    626   }
    627 }
    628 
    629 
    630 void MacroAssembler::PreparePrintfArgument(CPURegister reg,
    631                                            int* core_count,
    632                                            int* vfp_count,
    633                                            uint32_t* printf_type) {
    634   switch (reg.GetType()) {
    635     case CPURegister::kNoRegister:
    636       break;
    637     case CPURegister::kRRegister:
    638       VIXL_ASSERT(*core_count <= 4);
    639       if (*core_count < 4) Pop(Register(*core_count));
    640       *core_count += 1;
    641       break;
    642     case CPURegister::kSRegister:
    643       VIXL_ASSERT(*vfp_count < 4);
    644       *printf_type |= 1 << (*core_count + *vfp_count - 1);
    645       Vpop(Untyped32, SRegisterList(SRegister(*vfp_count * 2)));
    646       Vcvt(F64, F32, DRegister(*vfp_count), SRegister(*vfp_count * 2));
    647       *vfp_count += 1;
    648       break;
    649     case CPURegister::kDRegister:
    650       VIXL_ASSERT(*vfp_count < 4);
    651       *printf_type |= 1 << (*core_count + *vfp_count - 1);
    652       Vpop(Untyped64, DRegisterList(DRegister(*vfp_count)));
    653       *vfp_count += 1;
    654       break;
    655     case CPURegister::kQRegister:
    656       VIXL_UNIMPLEMENTED();
    657       break;
    658   }
    659 }
    660 
    661 
    662 void MacroAssembler::Delegate(InstructionType type,
    663                               InstructionCondROp instruction,
    664                               Condition cond,
    665                               Register rn,
    666                               const Operand& operand) {
    667   VIXL_ASSERT((type == kMovt) || (type == kSxtb16) || (type == kTeq) ||
    668               (type == kUxtb16));
    669 
    670   if (type == kMovt) {
    671     VIXL_ABORT_WITH_MSG("`Movt` expects a 16-bit immediate.\n");
    672   }
    673 
    674   // This delegate only supports teq with immediates.
    675   CONTEXT_SCOPE;
    676   if ((type == kTeq) && operand.IsImmediate()) {
    677     UseScratchRegisterScope temps(this);
    678     Register scratch = temps.Acquire();
    679     HandleOutOfBoundsImmediate(cond, scratch, operand.GetImmediate());
    680     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    681     teq(cond, rn, scratch);
    682     return;
    683   }
    684   Assembler::Delegate(type, instruction, cond, rn, operand);
    685 }
    686 
    687 
    688 void MacroAssembler::Delegate(InstructionType type,
    689                               InstructionCondSizeROp instruction,
    690                               Condition cond,
    691                               EncodingSize size,
    692                               Register rn,
    693                               const Operand& operand) {
    694   CONTEXT_SCOPE;
    695   VIXL_ASSERT(size.IsBest());
    696   VIXL_ASSERT((type == kCmn) || (type == kCmp) || (type == kMov) ||
    697               (type == kMovs) || (type == kMvn) || (type == kMvns) ||
    698               (type == kSxtb) || (type == kSxth) || (type == kTst) ||
    699               (type == kUxtb) || (type == kUxth));
    700   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
    701     VIXL_ASSERT((type != kMov) || (type != kMovs));
    702     InstructionCondRROp shiftop = NULL;
    703     switch (operand.GetShift().GetType()) {
    704       case LSL:
    705         shiftop = &Assembler::lsl;
    706         break;
    707       case LSR:
    708         shiftop = &Assembler::lsr;
    709         break;
    710       case ASR:
    711         shiftop = &Assembler::asr;
    712         break;
    713       case RRX:
    714         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
    715         VIXL_UNREACHABLE();
    716         break;
    717       case ROR:
    718         shiftop = &Assembler::ror;
    719         break;
    720       default:
    721         VIXL_UNREACHABLE();
    722     }
    723     if (shiftop != NULL) {
    724       UseScratchRegisterScope temps(this);
    725       Register scratch = temps.Acquire();
    726       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
    727       (this->*shiftop)(cond,
    728                        scratch,
    729                        operand.GetBaseRegister(),
    730                        operand.GetShiftRegister());
    731       (this->*instruction)(cond, size, rn, scratch);
    732       return;
    733     }
    734   }
    735   if (operand.IsImmediate()) {
    736     uint32_t imm = operand.GetImmediate();
    737     switch (type) {
    738       case kMov:
    739       case kMovs:
    740         if (!rn.IsPC()) {
    741           // Immediate is too large, but not using PC, so handle with mov{t}.
    742           HandleOutOfBoundsImmediate(cond, rn, imm);
    743           if (type == kMovs) {
    744             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    745             tst(cond, rn, rn);
    746           }
    747           return;
    748         } else if (type == kMov) {
    749           VIXL_ASSERT(IsUsingA32() || cond.Is(al));
    750           // Immediate is too large and using PC, so handle using a temporary
    751           // register.
    752           UseScratchRegisterScope temps(this);
    753           Register scratch = temps.Acquire();
    754           HandleOutOfBoundsImmediate(al, scratch, imm);
    755           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    756           bx(cond, scratch);
    757           return;
    758         }
    759         break;
    760       case kCmn:
    761       case kCmp:
    762         if (IsUsingA32() || !rn.IsPC()) {
    763           UseScratchRegisterScope temps(this);
    764           Register scratch = temps.Acquire();
    765           HandleOutOfBoundsImmediate(cond, scratch, imm);
    766           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    767           (this->*instruction)(cond, size, rn, scratch);
    768           return;
    769         }
    770         break;
    771       case kMvn:
    772       case kMvns:
    773         if (!rn.IsPC()) {
    774           UseScratchRegisterScope temps(this);
    775           Register scratch = temps.Acquire();
    776           HandleOutOfBoundsImmediate(cond, scratch, imm);
    777           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    778           (this->*instruction)(cond, size, rn, scratch);
    779           return;
    780         }
    781         break;
    782       case kTst:
    783         if (IsUsingA32() || !rn.IsPC()) {
    784           UseScratchRegisterScope temps(this);
    785           Register scratch = temps.Acquire();
    786           HandleOutOfBoundsImmediate(cond, scratch, imm);
    787           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    788           (this->*instruction)(cond, size, rn, scratch);
    789           return;
    790         }
    791         break;
    792       default:  // kSxtb, Sxth, Uxtb, Uxth
    793         break;
    794     }
    795   }
    796   Assembler::Delegate(type, instruction, cond, size, rn, operand);
    797 }
    798 
    799 
    800 void MacroAssembler::Delegate(InstructionType type,
    801                               InstructionCondRROp instruction,
    802                               Condition cond,
    803                               Register rd,
    804                               Register rn,
    805                               const Operand& operand) {
    806   if ((type == kSxtab) || (type == kSxtab16) || (type == kSxtah) ||
    807       (type == kUxtab) || (type == kUxtab16) || (type == kUxtah) ||
    808       (type == kPkhbt) || (type == kPkhtb)) {
    809     UnimplementedDelegate(type);
    810     return;
    811   }
    812 
    813   // This delegate only handles the following instructions.
    814   VIXL_ASSERT((type == kOrn) || (type == kOrns) || (type == kRsc) ||
    815               (type == kRscs));
    816   CONTEXT_SCOPE;
    817 
    818   // T32 does not support register shifted register operands, emulate it.
    819   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
    820     InstructionCondRROp shiftop = NULL;
    821     switch (operand.GetShift().GetType()) {
    822       case LSL:
    823         shiftop = &Assembler::lsl;
    824         break;
    825       case LSR:
    826         shiftop = &Assembler::lsr;
    827         break;
    828       case ASR:
    829         shiftop = &Assembler::asr;
    830         break;
    831       case RRX:
    832         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
    833         VIXL_UNREACHABLE();
    834         break;
    835       case ROR:
    836         shiftop = &Assembler::ror;
    837         break;
    838       default:
    839         VIXL_UNREACHABLE();
    840     }
    841     if (shiftop != NULL) {
    842       UseScratchRegisterScope temps(this);
    843       Register rm = operand.GetBaseRegister();
    844       Register rs = operand.GetShiftRegister();
    845       // Try to use rd as a scratch register. We can do this if it aliases rs or
    846       // rm (because we read them in the first instruction), but not rn.
    847       if (!rd.Is(rn)) temps.Include(rd);
    848       Register scratch = temps.Acquire();
    849       // TODO: The scope length was measured empirically. We should analyse the
    850       // worst-case size and add targetted tests.
    851       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
    852       (this->*shiftop)(cond, scratch, rm, rs);
    853       (this->*instruction)(cond, rd, rn, scratch);
    854       return;
    855     }
    856   }
    857 
    858   // T32 does not have a Rsc instruction, negate the lhs input and turn it into
    859   // an Adc. Adc and Rsc are equivalent using a bitwise NOT:
    860   //   adc rd, rn, operand <-> rsc rd, NOT(rn), operand
    861   if (IsUsingT32() && ((type == kRsc) || (type == kRscs))) {
    862     // The RegisterShiftRegister case should have been handled above.
    863     VIXL_ASSERT(!operand.IsRegisterShiftedRegister());
    864     UseScratchRegisterScope temps(this);
    865     // Try to use rd as a scratch register. We can do this if it aliases rn
    866     // (because we read it in the first instruction), but not rm.
    867     temps.Include(rd);
    868     temps.Exclude(operand);
    869     Register negated_rn = temps.Acquire();
    870     {
    871       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    872       mvn(cond, negated_rn, rn);
    873     }
    874     if (type == kRsc) {
    875       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    876       adc(cond, rd, negated_rn, operand);
    877       return;
    878     }
    879     // TODO: We shouldn't have to specify how much space the next instruction
    880     // needs.
    881     CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
    882     adcs(cond, rd, negated_rn, operand);
    883     return;
    884   }
    885 
    886   if (operand.IsImmediate()) {
    887     // If the immediate can be encoded when inverted, turn Orn into Orr.
    888     // Otherwise rely on HandleOutOfBoundsImmediate to generate a series of
    889     // mov.
    890     int32_t imm = operand.GetSignedImmediate();
    891     if (((type == kOrn) || (type == kOrns)) && IsModifiedImmediate(~imm)) {
    892       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    893       switch (type) {
    894         case kOrn:
    895           orr(cond, rd, rn, ~imm);
    896           return;
    897         case kOrns:
    898           orrs(cond, rd, rn, ~imm);
    899           return;
    900         default:
    901           VIXL_UNREACHABLE();
    902           break;
    903       }
    904     }
    905   }
    906 
    907   // A32 does not have a Orn instruction, negate the rhs input and turn it into
    908   // a Orr.
    909   if (IsUsingA32() && ((type == kOrn) || (type == kOrns))) {
    910     // TODO: orn r0, r1, imm -> orr r0, r1, neg(imm) if doable
    911     //  mvn r0, r2
    912     //  orr r0, r1, r0
    913     Register scratch;
    914     UseScratchRegisterScope temps(this);
    915     // Try to use rd as a scratch register. We can do this if it aliases rs or
    916     // rm (because we read them in the first instruction), but not rn.
    917     if (!rd.Is(rn)) temps.Include(rd);
    918     scratch = temps.Acquire();
    919     {
    920       // TODO: We shouldn't have to specify how much space the next instruction
    921       // needs.
    922       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
    923       mvn(cond, scratch, operand);
    924     }
    925     if (type == kOrns) {
    926       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    927       orrs(cond, rd, rn, scratch);
    928       return;
    929     }
    930     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    931     orr(cond, rd, rn, scratch);
    932     return;
    933   }
    934 
    935   if (operand.IsImmediate()) {
    936     UseScratchRegisterScope temps(this);
    937     // Allow using the destination as a scratch register if possible.
    938     if (!rd.Is(rn)) temps.Include(rd);
    939     Register scratch = temps.Acquire();
    940     int32_t imm = operand.GetSignedImmediate();
    941     HandleOutOfBoundsImmediate(cond, scratch, imm);
    942     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
    943     (this->*instruction)(cond, rd, rn, scratch);
    944     return;
    945   }
    946   Assembler::Delegate(type, instruction, cond, rd, rn, operand);
    947 }
    948 
    949 
    950 void MacroAssembler::Delegate(InstructionType type,
    951                               InstructionCondSizeRL instruction,
    952                               Condition cond,
    953                               EncodingSize size,
    954                               Register rd,
    955                               Location* location) {
    956   VIXL_ASSERT((type == kLdr) || (type == kAdr));
    957 
    958   CONTEXT_SCOPE;
    959   VIXL_ASSERT(size.IsBest());
    960 
    961   if ((type == kLdr) && location->IsBound()) {
    962     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
    963     UseScratchRegisterScope temps(this);
    964     temps.Include(rd);
    965     uint32_t mask = GetOffsetMask(type, Offset);
    966     ldr(rd, MemOperandComputationHelper(cond, temps.Acquire(), location, mask));
    967     return;
    968   }
    969 
    970   Assembler::Delegate(type, instruction, cond, size, rd, location);
    971 }
    972 
    973 
    974 bool MacroAssembler::GenerateSplitInstruction(
    975     InstructionCondSizeRROp instruction,
    976     Condition cond,
    977     Register rd,
    978     Register rn,
    979     uint32_t imm,
    980     uint32_t mask) {
    981   uint32_t high = imm & ~mask;
    982   if (!IsModifiedImmediate(high) && !rn.IsPC()) return false;
    983   // If high is a modified immediate, we can perform the operation with
    984   // only 2 instructions.
    985   // Else, if rn is PC, we want to avoid moving PC into a temporary.
    986   // Therefore, we also use the pattern even if the second call may
    987   // generate 3 instructions.
    988   uint32_t low = imm & mask;
    989   CodeBufferCheckScope scope(this,
    990                              (rn.IsPC() ? 4 : 2) * kMaxInstructionSizeInBytes);
    991   (this->*instruction)(cond, Best, rd, rn, low);
    992   (this->*instruction)(cond, Best, rd, rd, high);
    993   return true;
    994 }
    995 
    996 
    997 void MacroAssembler::Delegate(InstructionType type,
    998                               InstructionCondSizeRROp instruction,
    999                               Condition cond,
   1000                               EncodingSize size,
   1001                               Register rd,
   1002                               Register rn,
   1003                               const Operand& operand) {
   1004   VIXL_ASSERT(
   1005       (type == kAdc) || (type == kAdcs) || (type == kAdd) || (type == kAdds) ||
   1006       (type == kAnd) || (type == kAnds) || (type == kAsr) || (type == kAsrs) ||
   1007       (type == kBic) || (type == kBics) || (type == kEor) || (type == kEors) ||
   1008       (type == kLsl) || (type == kLsls) || (type == kLsr) || (type == kLsrs) ||
   1009       (type == kOrr) || (type == kOrrs) || (type == kRor) || (type == kRors) ||
   1010       (type == kRsb) || (type == kRsbs) || (type == kSbc) || (type == kSbcs) ||
   1011       (type == kSub) || (type == kSubs));
   1012 
   1013   CONTEXT_SCOPE;
   1014   VIXL_ASSERT(size.IsBest());
   1015   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
   1016     InstructionCondRROp shiftop = NULL;
   1017     switch (operand.GetShift().GetType()) {
   1018       case LSL:
   1019         shiftop = &Assembler::lsl;
   1020         break;
   1021       case LSR:
   1022         shiftop = &Assembler::lsr;
   1023         break;
   1024       case ASR:
   1025         shiftop = &Assembler::asr;
   1026         break;
   1027       case RRX:
   1028         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
   1029         VIXL_UNREACHABLE();
   1030         break;
   1031       case ROR:
   1032         shiftop = &Assembler::ror;
   1033         break;
   1034       default:
   1035         VIXL_UNREACHABLE();
   1036     }
   1037     if (shiftop != NULL) {
   1038       UseScratchRegisterScope temps(this);
   1039       Register rm = operand.GetBaseRegister();
   1040       Register rs = operand.GetShiftRegister();
   1041       // Try to use rd as a scratch register. We can do this if it aliases rs or
   1042       // rm (because we read them in the first instruction), but not rn.
   1043       if (!rd.Is(rn)) temps.Include(rd);
   1044       Register scratch = temps.Acquire();
   1045       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
   1046       (this->*shiftop)(cond, scratch, rm, rs);
   1047       (this->*instruction)(cond, size, rd, rn, scratch);
   1048       return;
   1049     }
   1050   }
   1051   if (operand.IsImmediate()) {
   1052     int32_t imm = operand.GetSignedImmediate();
   1053     if (ImmediateT32::IsImmediateT32(~imm)) {
   1054       if (IsUsingT32()) {
   1055         switch (type) {
   1056           case kOrr:
   1057             orn(cond, rd, rn, ~imm);
   1058             return;
   1059           case kOrrs:
   1060             orns(cond, rd, rn, ~imm);
   1061             return;
   1062           default:
   1063             break;
   1064         }
   1065       }
   1066     }
   1067     if (imm < 0) {
   1068       InstructionCondSizeRROp asmcb = NULL;
   1069       // Add and sub are equivalent using an arithmetic negation:
   1070       //   add rd, rn, #imm <-> sub rd, rn, - #imm
   1071       // Add and sub with carry are equivalent using a bitwise NOT:
   1072       //   adc rd, rn, #imm <-> sbc rd, rn, NOT #imm
   1073       switch (type) {
   1074         case kAdd:
   1075           asmcb = &Assembler::sub;
   1076           imm = -imm;
   1077           break;
   1078         case kAdds:
   1079           asmcb = &Assembler::subs;
   1080           imm = -imm;
   1081           break;
   1082         case kSub:
   1083           asmcb = &Assembler::add;
   1084           imm = -imm;
   1085           break;
   1086         case kSubs:
   1087           asmcb = &Assembler::adds;
   1088           imm = -imm;
   1089           break;
   1090         case kAdc:
   1091           asmcb = &Assembler::sbc;
   1092           imm = ~imm;
   1093           break;
   1094         case kAdcs:
   1095           asmcb = &Assembler::sbcs;
   1096           imm = ~imm;
   1097           break;
   1098         case kSbc:
   1099           asmcb = &Assembler::adc;
   1100           imm = ~imm;
   1101           break;
   1102         case kSbcs:
   1103           asmcb = &Assembler::adcs;
   1104           imm = ~imm;
   1105           break;
   1106         default:
   1107           break;
   1108       }
   1109       if (asmcb != NULL) {
   1110         CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
   1111         (this->*asmcb)(cond, size, rd, rn, Operand(imm));
   1112         return;
   1113       }
   1114     }
   1115 
   1116     // When rn is PC, only handle negative offsets. The correct way to handle
   1117     // positive offsets isn't clear; does the user want the offset from the
   1118     // start of the macro, or from the end (to allow a certain amount of space)?
   1119     // When type is Add or Sub, imm is always positive (imm < 0 has just been
   1120     // handled and imm == 0 would have been generated without the need of a
   1121     // delegate). Therefore, only add to PC is forbidden here.
   1122     if ((((type == kAdd) && !rn.IsPC()) || (type == kSub)) &&
   1123         (IsUsingA32() || (!rd.IsPC() && !rn.IsPC()))) {
   1124       VIXL_ASSERT(imm > 0);
   1125       // Try to break the constant into two modified immediates.
   1126       // For T32 also try to break the constant into one imm12 and one modified
   1127       // immediate. Count the trailing zeroes and get the biggest even value.
   1128       int trailing_zeroes = CountTrailingZeros(imm) & ~1u;
   1129       uint32_t mask = ((trailing_zeroes < 4) && IsUsingT32())
   1130                           ? 0xfff
   1131                           : (0xff << trailing_zeroes);
   1132       if (GenerateSplitInstruction(instruction, cond, rd, rn, imm, mask)) {
   1133         return;
   1134       }
   1135       InstructionCondSizeRROp asmcb = NULL;
   1136       switch (type) {
   1137         case kAdd:
   1138           asmcb = &Assembler::sub;
   1139           break;
   1140         case kSub:
   1141           asmcb = &Assembler::add;
   1142           break;
   1143         default:
   1144           VIXL_UNREACHABLE();
   1145       }
   1146       if (GenerateSplitInstruction(asmcb, cond, rd, rn, -imm, mask)) {
   1147         return;
   1148       }
   1149     }
   1150 
   1151     UseScratchRegisterScope temps(this);
   1152     // Allow using the destination as a scratch register if possible.
   1153     if (!rd.Is(rn)) temps.Include(rd);
   1154     if (rn.IsPC()) {
   1155       // If we're reading the PC, we need to do it in the first instruction,
   1156       // otherwise we'll read the wrong value. We rely on this to handle the
   1157       // long-range PC-relative MemOperands which can result from user-managed
   1158       // literals.
   1159 
   1160       // Only handle negative offsets. The correct way to handle positive
   1161       // offsets isn't clear; does the user want the offset from the start of
   1162       // the macro, or from the end (to allow a certain amount of space)?
   1163       bool offset_is_negative_or_zero = (imm <= 0);
   1164       switch (type) {
   1165         case kAdd:
   1166         case kAdds:
   1167           offset_is_negative_or_zero = (imm <= 0);
   1168           break;
   1169         case kSub:
   1170         case kSubs:
   1171           offset_is_negative_or_zero = (imm >= 0);
   1172           break;
   1173         case kAdc:
   1174         case kAdcs:
   1175           offset_is_negative_or_zero = (imm < 0);
   1176           break;
   1177         case kSbc:
   1178         case kSbcs:
   1179           offset_is_negative_or_zero = (imm > 0);
   1180           break;
   1181         default:
   1182           break;
   1183       }
   1184       if (offset_is_negative_or_zero) {
   1185         {
   1186           rn = temps.Acquire();
   1187           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1188           mov(cond, rn, pc);
   1189         }
   1190         // Recurse rather than falling through, to try to get the immediate into
   1191         // a single instruction.
   1192         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1193         (this->*instruction)(cond, size, rd, rn, operand);
   1194         return;
   1195       }
   1196     } else {
   1197       Register scratch = temps.Acquire();
   1198       // TODO: The scope length was measured empirically. We should analyse the
   1199       // worst-case size and add targetted tests.
   1200       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1201       mov(cond, scratch, operand.GetImmediate());
   1202       (this->*instruction)(cond, size, rd, rn, scratch);
   1203       return;
   1204     }
   1205   }
   1206   Assembler::Delegate(type, instruction, cond, size, rd, rn, operand);
   1207 }
   1208 
   1209 
   1210 void MacroAssembler::Delegate(InstructionType type,
   1211                               InstructionRL instruction,
   1212                               Register rn,
   1213                               Location* location) {
   1214   VIXL_ASSERT((type == kCbz) || (type == kCbnz));
   1215 
   1216   CONTEXT_SCOPE;
   1217   CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
   1218   if (IsUsingA32()) {
   1219     if (type == kCbz) {
   1220       VIXL_ABORT_WITH_MSG("Cbz is only available for T32.\n");
   1221     } else {
   1222       VIXL_ABORT_WITH_MSG("Cbnz is only available for T32.\n");
   1223     }
   1224   } else if (rn.IsLow()) {
   1225     switch (type) {
   1226       case kCbnz: {
   1227         Label done;
   1228         cbz(rn, &done);
   1229         b(location);
   1230         Bind(&done);
   1231         return;
   1232       }
   1233       case kCbz: {
   1234         Label done;
   1235         cbnz(rn, &done);
   1236         b(location);
   1237         Bind(&done);
   1238         return;
   1239       }
   1240       default:
   1241         break;
   1242     }
   1243   }
   1244   Assembler::Delegate(type, instruction, rn, location);
   1245 }
   1246 
   1247 
   1248 template <typename T>
   1249 static inline bool IsI64BitPattern(T imm) {
   1250   for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
   1251     if (((imm & mask) != mask) && ((imm & mask) != 0)) return false;
   1252   }
   1253   return true;
   1254 }
   1255 
   1256 
   1257 template <typename T>
   1258 static inline bool IsI8BitPattern(T imm) {
   1259   uint8_t imm8 = imm & 0xff;
   1260   for (unsigned rep = sizeof(T) - 1; rep > 0; rep--) {
   1261     imm >>= 8;
   1262     if ((imm & 0xff) != imm8) return false;
   1263   }
   1264   return true;
   1265 }
   1266 
   1267 
   1268 static inline bool CanBeInverted(uint32_t imm32) {
   1269   uint32_t fill8 = 0;
   1270 
   1271   if ((imm32 & 0xffffff00) == 0xffffff00) {
   1272     //    11111111 11111111 11111111 abcdefgh
   1273     return true;
   1274   }
   1275   if (((imm32 & 0xff) == 0) || ((imm32 & 0xff) == 0xff)) {
   1276     fill8 = imm32 & 0xff;
   1277     imm32 >>= 8;
   1278     if ((imm32 >> 8) == 0xffff) {
   1279       //    11111111 11111111 abcdefgh 00000000
   1280       // or 11111111 11111111 abcdefgh 11111111
   1281       return true;
   1282     }
   1283     if ((imm32 & 0xff) == fill8) {
   1284       imm32 >>= 8;
   1285       if ((imm32 >> 8) == 0xff) {
   1286         //    11111111 abcdefgh 00000000 00000000
   1287         // or 11111111 abcdefgh 11111111 11111111
   1288         return true;
   1289       }
   1290       if ((fill8 == 0xff) && ((imm32 & 0xff) == 0xff)) {
   1291         //    abcdefgh 11111111 11111111 11111111
   1292         return true;
   1293       }
   1294     }
   1295   }
   1296   return false;
   1297 }
   1298 
   1299 
   1300 template <typename RES, typename T>
   1301 static inline RES replicate(T imm) {
   1302   VIXL_ASSERT((sizeof(RES) > sizeof(T)) &&
   1303               (((sizeof(RES) / sizeof(T)) * sizeof(T)) == sizeof(RES)));
   1304   RES res = imm;
   1305   for (unsigned i = sizeof(RES) / sizeof(T) - 1; i > 0; i--) {
   1306     res = (res << (sizeof(T) * 8)) | imm;
   1307   }
   1308   return res;
   1309 }
   1310 
   1311 
   1312 void MacroAssembler::Delegate(InstructionType type,
   1313                               InstructionCondDtSSop instruction,
   1314                               Condition cond,
   1315                               DataType dt,
   1316                               SRegister rd,
   1317                               const SOperand& operand) {
   1318   CONTEXT_SCOPE;
   1319   if (type == kVmov) {
   1320     if (operand.IsImmediate() && dt.Is(F32)) {
   1321       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
   1322       if (neon_imm.CanConvert<float>()) {
   1323         // movw ip, imm16
   1324         // movk ip, imm16
   1325         // vmov s0, ip
   1326         UseScratchRegisterScope temps(this);
   1327         Register scratch = temps.Acquire();
   1328         float f = neon_imm.GetImmediate<float>();
   1329         // TODO: The scope length was measured empirically. We should analyse
   1330         // the
   1331         // worst-case size and add targetted tests.
   1332         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1333         mov(cond, scratch, FloatToRawbits(f));
   1334         vmov(cond, rd, scratch);
   1335         return;
   1336       }
   1337     }
   1338   }
   1339   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
   1340 }
   1341 
   1342 
   1343 void MacroAssembler::Delegate(InstructionType type,
   1344                               InstructionCondDtDDop instruction,
   1345                               Condition cond,
   1346                               DataType dt,
   1347                               DRegister rd,
   1348                               const DOperand& operand) {
   1349   CONTEXT_SCOPE;
   1350   if (type == kVmov) {
   1351     if (operand.IsImmediate()) {
   1352       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
   1353       switch (dt.GetValue()) {
   1354         case I32:
   1355           if (neon_imm.CanConvert<uint32_t>()) {
   1356             uint32_t imm = neon_imm.GetImmediate<uint32_t>();
   1357             // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
   1358             if (IsI8BitPattern(imm)) {
   1359               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1360               vmov(cond, I8, rd, imm & 0xff);
   1361               return;
   1362             }
   1363             // vmov.i32 d0, 0xff0000ff will translate into
   1364             // vmov.i64 d0, 0xff0000ffff0000ff
   1365             if (IsI64BitPattern(imm)) {
   1366               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1367               vmov(cond, I64, rd, replicate<uint64_t>(imm));
   1368               return;
   1369             }
   1370             // vmov.i32 d0, 0xffab0000 will translate into
   1371             // vmvn.i32 d0, 0x0054ffff
   1372             if (cond.Is(al) && CanBeInverted(imm)) {
   1373               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1374               vmvn(I32, rd, ~imm);
   1375               return;
   1376             }
   1377           }
   1378           break;
   1379         case I16:
   1380           if (neon_imm.CanConvert<uint16_t>()) {
   1381             uint16_t imm = neon_imm.GetImmediate<uint16_t>();
   1382             // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
   1383             if (IsI8BitPattern(imm)) {
   1384               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1385               vmov(cond, I8, rd, imm & 0xff);
   1386               return;
   1387             }
   1388           }
   1389           break;
   1390         case I64:
   1391           if (neon_imm.CanConvert<uint64_t>()) {
   1392             uint64_t imm = neon_imm.GetImmediate<uint64_t>();
   1393             // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
   1394             if (IsI8BitPattern(imm)) {
   1395               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1396               vmov(cond, I8, rd, imm & 0xff);
   1397               return;
   1398             }
   1399             // mov ip, lo(imm64)
   1400             // vdup d0, ip
   1401             // vdup is prefered to 'vmov d0[0]' as d0[1] does not need to be
   1402             // preserved
   1403             {
   1404               UseScratchRegisterScope temps(this);
   1405               Register scratch = temps.Acquire();
   1406               {
   1407                 // TODO: The scope length was measured empirically. We should
   1408                 // analyse the
   1409                 // worst-case size and add targetted tests.
   1410                 CodeBufferCheckScope scope(this,
   1411                                            2 * kMaxInstructionSizeInBytes);
   1412                 mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
   1413               }
   1414               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1415               vdup(cond, Untyped32, rd, scratch);
   1416             }
   1417             // mov ip, hi(imm64)
   1418             // vmov d0[1], ip
   1419             {
   1420               UseScratchRegisterScope temps(this);
   1421               Register scratch = temps.Acquire();
   1422               {
   1423                 // TODO: The scope length was measured empirically. We should
   1424                 // analyse the
   1425                 // worst-case size and add targetted tests.
   1426                 CodeBufferCheckScope scope(this,
   1427                                            2 * kMaxInstructionSizeInBytes);
   1428                 mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
   1429               }
   1430               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1431               vmov(cond, Untyped32, DRegisterLane(rd, 1), scratch);
   1432             }
   1433             return;
   1434           }
   1435           break;
   1436         default:
   1437           break;
   1438       }
   1439       VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
   1440       if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
   1441         // mov ip, imm32
   1442         // vdup.16 d0, ip
   1443         UseScratchRegisterScope temps(this);
   1444         Register scratch = temps.Acquire();
   1445         {
   1446           CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
   1447           mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
   1448         }
   1449         DataTypeValue vdup_dt = Untyped32;
   1450         switch (dt.GetValue()) {
   1451           case I16:
   1452             vdup_dt = Untyped16;
   1453             break;
   1454           case I32:
   1455             vdup_dt = Untyped32;
   1456             break;
   1457           default:
   1458             VIXL_UNREACHABLE();
   1459         }
   1460         CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1461         vdup(cond, vdup_dt, rd, scratch);
   1462         return;
   1463       }
   1464       if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
   1465         float f = neon_imm.GetImmediate<float>();
   1466         // Punt to vmov.i32
   1467         // TODO: The scope length was guessed based on the double case below. We
   1468         // should analyse the worst-case size and add targetted tests.
   1469         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1470         vmov(cond, I32, rd, FloatToRawbits(f));
   1471         return;
   1472       }
   1473       if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
   1474         // Punt to vmov.i64
   1475         double d = neon_imm.GetImmediate<double>();
   1476         // TODO: The scope length was measured empirically. We should analyse
   1477         // the
   1478         // worst-case size and add targetted tests.
   1479         CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
   1480         vmov(cond, I64, rd, DoubleToRawbits(d));
   1481         return;
   1482       }
   1483     }
   1484   }
   1485   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
   1486 }
   1487 
   1488 
   1489 void MacroAssembler::Delegate(InstructionType type,
   1490                               InstructionCondDtQQop instruction,
   1491                               Condition cond,
   1492                               DataType dt,
   1493                               QRegister rd,
   1494                               const QOperand& operand) {
   1495   CONTEXT_SCOPE;
   1496   if (type == kVmov) {
   1497     if (operand.IsImmediate()) {
   1498       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
   1499       switch (dt.GetValue()) {
   1500         case I32:
   1501           if (neon_imm.CanConvert<uint32_t>()) {
   1502             uint32_t imm = neon_imm.GetImmediate<uint32_t>();
   1503             // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
   1504             if (IsI8BitPattern(imm)) {
   1505               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1506               vmov(cond, I8, rd, imm & 0xff);
   1507               return;
   1508             }
   1509             // vmov.i32 d0, 0xff0000ff will translate into
   1510             // vmov.i64 d0, 0xff0000ffff0000ff
   1511             if (IsI64BitPattern(imm)) {
   1512               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1513               vmov(cond, I64, rd, replicate<uint64_t>(imm));
   1514               return;
   1515             }
   1516             // vmov.i32 d0, 0xffab0000 will translate into
   1517             // vmvn.i32 d0, 0x0054ffff
   1518             if (CanBeInverted(imm)) {
   1519               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1520               vmvn(cond, I32, rd, ~imm);
   1521               return;
   1522             }
   1523           }
   1524           break;
   1525         case I16:
   1526           if (neon_imm.CanConvert<uint16_t>()) {
   1527             uint16_t imm = neon_imm.GetImmediate<uint16_t>();
   1528             // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
   1529             if (IsI8BitPattern(imm)) {
   1530               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1531               vmov(cond, I8, rd, imm & 0xff);
   1532               return;
   1533             }
   1534           }
   1535           break;
   1536         case I64:
   1537           if (neon_imm.CanConvert<uint64_t>()) {
   1538             uint64_t imm = neon_imm.GetImmediate<uint64_t>();
   1539             // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
   1540             if (IsI8BitPattern(imm)) {
   1541               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1542               vmov(cond, I8, rd, imm & 0xff);
   1543               return;
   1544             }
   1545             // mov ip, lo(imm64)
   1546             // vdup q0, ip
   1547             // vdup is prefered to 'vmov d0[0]' as d0[1-3] don't need to be
   1548             // preserved
   1549             {
   1550               UseScratchRegisterScope temps(this);
   1551               Register scratch = temps.Acquire();
   1552               {
   1553                 CodeBufferCheckScope scope(this,
   1554                                            2 * kMaxInstructionSizeInBytes);
   1555                 mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
   1556               }
   1557               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1558               vdup(cond, Untyped32, rd, scratch);
   1559             }
   1560             // mov ip, hi(imm64)
   1561             // vmov.i32 d0[1], ip
   1562             // vmov d1, d0
   1563             {
   1564               UseScratchRegisterScope temps(this);
   1565               Register scratch = temps.Acquire();
   1566               {
   1567                 CodeBufferCheckScope scope(this,
   1568                                            2 * kMaxInstructionSizeInBytes);
   1569                 mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
   1570               }
   1571               {
   1572                 CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1573                 vmov(cond,
   1574                      Untyped32,
   1575                      DRegisterLane(rd.GetLowDRegister(), 1),
   1576                      scratch);
   1577               }
   1578               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1579               vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
   1580             }
   1581             return;
   1582           }
   1583           break;
   1584         default:
   1585           break;
   1586       }
   1587       VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
   1588       if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
   1589         // mov ip, imm32
   1590         // vdup.16 d0, ip
   1591         UseScratchRegisterScope temps(this);
   1592         Register scratch = temps.Acquire();
   1593         {
   1594           CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
   1595           mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
   1596         }
   1597         DataTypeValue vdup_dt = Untyped32;
   1598         switch (dt.GetValue()) {
   1599           case I16:
   1600             vdup_dt = Untyped16;
   1601             break;
   1602           case I32:
   1603             vdup_dt = Untyped32;
   1604             break;
   1605           default:
   1606             VIXL_UNREACHABLE();
   1607         }
   1608         CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1609         vdup(cond, vdup_dt, rd, scratch);
   1610         return;
   1611       }
   1612       if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
   1613         // Punt to vmov.i64
   1614         float f = neon_imm.GetImmediate<float>();
   1615         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1616         vmov(cond, I32, rd, FloatToRawbits(f));
   1617         return;
   1618       }
   1619       if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
   1620         // Use vmov to create the double in the low D register, then duplicate
   1621         // it into the high D register.
   1622         double d = neon_imm.GetImmediate<double>();
   1623         CodeBufferCheckScope scope(this, 7 * kMaxInstructionSizeInBytes);
   1624         vmov(cond, F64, rd.GetLowDRegister(), d);
   1625         vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
   1626         return;
   1627       }
   1628     }
   1629   }
   1630   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
   1631 }
   1632 
   1633 
   1634 void MacroAssembler::Delegate(InstructionType type,
   1635                               InstructionCondRL instruction,
   1636                               Condition cond,
   1637                               Register rt,
   1638                               Location* location) {
   1639   VIXL_ASSERT((type == kLdrb) || (type == kLdrh) || (type == kLdrsb) ||
   1640               (type == kLdrsh));
   1641 
   1642   CONTEXT_SCOPE;
   1643 
   1644   if (location->IsBound()) {
   1645     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
   1646     UseScratchRegisterScope temps(this);
   1647     temps.Include(rt);
   1648     Register scratch = temps.Acquire();
   1649     uint32_t mask = GetOffsetMask(type, Offset);
   1650     switch (type) {
   1651       case kLdrb:
   1652         ldrb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
   1653         return;
   1654       case kLdrh:
   1655         ldrh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
   1656         return;
   1657       case kLdrsb:
   1658         ldrsb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
   1659         return;
   1660       case kLdrsh:
   1661         ldrsh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
   1662         return;
   1663       default:
   1664         VIXL_UNREACHABLE();
   1665     }
   1666     return;
   1667   }
   1668 
   1669   Assembler::Delegate(type, instruction, cond, rt, location);
   1670 }
   1671 
   1672 
   1673 void MacroAssembler::Delegate(InstructionType type,
   1674                               InstructionCondRRL instruction,
   1675                               Condition cond,
   1676                               Register rt,
   1677                               Register rt2,
   1678                               Location* location) {
   1679   VIXL_ASSERT(type == kLdrd);
   1680 
   1681   CONTEXT_SCOPE;
   1682 
   1683   if (location->IsBound()) {
   1684     CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
   1685     UseScratchRegisterScope temps(this);
   1686     temps.Include(rt, rt2);
   1687     Register scratch = temps.Acquire();
   1688     uint32_t mask = GetOffsetMask(type, Offset);
   1689     ldrd(rt, rt2, MemOperandComputationHelper(cond, scratch, location, mask));
   1690     return;
   1691   }
   1692 
   1693   Assembler::Delegate(type, instruction, cond, rt, rt2, location);
   1694 }
   1695 
   1696 
   1697 void MacroAssembler::Delegate(InstructionType type,
   1698                               InstructionCondSizeRMop instruction,
   1699                               Condition cond,
   1700                               EncodingSize size,
   1701                               Register rd,
   1702                               const MemOperand& operand) {
   1703   CONTEXT_SCOPE;
   1704   VIXL_ASSERT(size.IsBest());
   1705   VIXL_ASSERT((type == kLdr) || (type == kLdrb) || (type == kLdrh) ||
   1706               (type == kLdrsb) || (type == kLdrsh) || (type == kStr) ||
   1707               (type == kStrb) || (type == kStrh));
   1708   if (operand.IsImmediate()) {
   1709     const Register& rn = operand.GetBaseRegister();
   1710     AddrMode addrmode = operand.GetAddrMode();
   1711     int32_t offset = operand.GetOffsetImmediate();
   1712     uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
   1713     // Try to maximize the offset used by the MemOperand (load_store_offset).
   1714     // Add the part which can't be used by the MemOperand (add_offset).
   1715     uint32_t load_store_offset = offset & extra_offset_mask;
   1716     uint32_t add_offset = offset & ~extra_offset_mask;
   1717     if ((add_offset != 0) &&
   1718         (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
   1719       load_store_offset = 0;
   1720       add_offset = offset;
   1721     }
   1722     switch (addrmode) {
   1723       case PreIndex:
   1724         // Avoid the unpredictable case 'str r0, [r0, imm]!'
   1725         if (!rn.Is(rd)) {
   1726           // Pre-Indexed case:
   1727           // ldr r0, [r1, 12345]! will translate into
   1728           //   add r1, r1, 12345
   1729           //   ldr r0, [r1]
   1730           {
   1731             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1732             add(cond, rn, rn, add_offset);
   1733           }
   1734           {
   1735             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1736             (this->*instruction)(cond,
   1737                                  size,
   1738                                  rd,
   1739                                  MemOperand(rn, load_store_offset, PreIndex));
   1740           }
   1741           return;
   1742         }
   1743         break;
   1744       case Offset: {
   1745         UseScratchRegisterScope temps(this);
   1746         // Allow using the destination as a scratch register if possible.
   1747         if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
   1748             !rd.Is(rn)) {
   1749           temps.Include(rd);
   1750         }
   1751         Register scratch = temps.Acquire();
   1752         // Offset case:
   1753         // ldr r0, [r1, 12345] will translate into
   1754         //   add r0, r1, 12345
   1755         //   ldr r0, [r0]
   1756         {
   1757           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1758           add(cond, scratch, rn, add_offset);
   1759         }
   1760         {
   1761           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1762           (this->*instruction)(cond,
   1763                                size,
   1764                                rd,
   1765                                MemOperand(scratch, load_store_offset));
   1766         }
   1767         return;
   1768       }
   1769       case PostIndex:
   1770         // Avoid the unpredictable case 'ldr r0, [r0], imm'
   1771         if (!rn.Is(rd)) {
   1772           // Post-indexed case:
   1773           // ldr r0. [r1], imm32 will translate into
   1774           //   ldr r0, [r1]
   1775           //   movw ip. imm32 & 0xffffffff
   1776           //   movt ip, imm32 >> 16
   1777           //   add r1, r1, ip
   1778           {
   1779             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1780             (this->*instruction)(cond,
   1781                                  size,
   1782                                  rd,
   1783                                  MemOperand(rn, load_store_offset, PostIndex));
   1784           }
   1785           {
   1786             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1787             add(cond, rn, rn, add_offset);
   1788           }
   1789           return;
   1790         }
   1791         break;
   1792     }
   1793   } else if (operand.IsPlainRegister()) {
   1794     const Register& rn = operand.GetBaseRegister();
   1795     AddrMode addrmode = operand.GetAddrMode();
   1796     const Register& rm = operand.GetOffsetRegister();
   1797     if (rm.IsPC()) {
   1798       VIXL_ABORT_WITH_MSG(
   1799           "The MacroAssembler does not convert loads and stores with a PC "
   1800           "offset register.\n");
   1801     }
   1802     if (rn.IsPC()) {
   1803       if (addrmode == Offset) {
   1804         if (IsUsingT32()) {
   1805           VIXL_ABORT_WITH_MSG(
   1806               "The MacroAssembler does not convert loads and stores with a PC "
   1807               "base register for T32.\n");
   1808         }
   1809       } else {
   1810         VIXL_ABORT_WITH_MSG(
   1811             "The MacroAssembler does not convert loads and stores with a PC "
   1812             "base register in pre-index or post-index mode.\n");
   1813       }
   1814     }
   1815     switch (addrmode) {
   1816       case PreIndex:
   1817         // Avoid the unpredictable case 'str r0, [r0, imm]!'
   1818         if (!rn.Is(rd)) {
   1819           // Pre-Indexed case:
   1820           // ldr r0, [r1, r2]! will translate into
   1821           //   add r1, r1, r2
   1822           //   ldr r0, [r1]
   1823           {
   1824             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1825             if (operand.GetSign().IsPlus()) {
   1826               add(cond, rn, rn, rm);
   1827             } else {
   1828               sub(cond, rn, rn, rm);
   1829             }
   1830           }
   1831           {
   1832             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1833             (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
   1834           }
   1835           return;
   1836         }
   1837         break;
   1838       case Offset: {
   1839         UseScratchRegisterScope temps(this);
   1840         // Allow using the destination as a scratch register if this is not a
   1841         // store.
   1842         // Avoid using PC as a temporary as this has side-effects.
   1843         if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
   1844             !rd.IsPC()) {
   1845           temps.Include(rd);
   1846         }
   1847         Register scratch = temps.Acquire();
   1848         // Offset case:
   1849         // ldr r0, [r1, r2] will translate into
   1850         //   add r0, r1, r2
   1851         //   ldr r0, [r0]
   1852         {
   1853           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1854           if (operand.GetSign().IsPlus()) {
   1855             add(cond, scratch, rn, rm);
   1856           } else {
   1857             sub(cond, scratch, rn, rm);
   1858           }
   1859         }
   1860         {
   1861           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1862           (this->*instruction)(cond, size, rd, MemOperand(scratch, Offset));
   1863         }
   1864         return;
   1865       }
   1866       case PostIndex:
   1867         // Avoid the unpredictable case 'ldr r0, [r0], imm'
   1868         if (!rn.Is(rd)) {
   1869           // Post-indexed case:
   1870           // ldr r0. [r1], r2 will translate into
   1871           //   ldr r0, [r1]
   1872           //   add r1, r1, r2
   1873           {
   1874             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1875             (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
   1876           }
   1877           {
   1878             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1879             if (operand.GetSign().IsPlus()) {
   1880               add(cond, rn, rn, rm);
   1881             } else {
   1882               sub(cond, rn, rn, rm);
   1883             }
   1884           }
   1885           return;
   1886         }
   1887         break;
   1888     }
   1889   }
   1890   Assembler::Delegate(type, instruction, cond, size, rd, operand);
   1891 }
   1892 
   1893 
   1894 void MacroAssembler::Delegate(InstructionType type,
   1895                               InstructionCondRRMop instruction,
   1896                               Condition cond,
   1897                               Register rt,
   1898                               Register rt2,
   1899                               const MemOperand& operand) {
   1900   if ((type == kLdaexd) || (type == kLdrexd) || (type == kStlex) ||
   1901       (type == kStlexb) || (type == kStlexh) || (type == kStrex) ||
   1902       (type == kStrexb) || (type == kStrexh)) {
   1903     UnimplementedDelegate(type);
   1904     return;
   1905   }
   1906 
   1907   VIXL_ASSERT((type == kLdrd) || (type == kStrd));
   1908 
   1909   CONTEXT_SCOPE;
   1910 
   1911   // TODO: Should we allow these cases?
   1912   if (IsUsingA32()) {
   1913     // The first register needs to be even.
   1914     if ((rt.GetCode() & 1) != 0) {
   1915       UnimplementedDelegate(type);
   1916       return;
   1917     }
   1918     // Registers need to be adjacent.
   1919     if (((rt.GetCode() + 1) % kNumberOfRegisters) != rt2.GetCode()) {
   1920       UnimplementedDelegate(type);
   1921       return;
   1922     }
   1923     // LDRD lr, pc [...] is not allowed.
   1924     if (rt.Is(lr)) {
   1925       UnimplementedDelegate(type);
   1926       return;
   1927     }
   1928   }
   1929 
   1930   if (operand.IsImmediate()) {
   1931     const Register& rn = operand.GetBaseRegister();
   1932     AddrMode addrmode = operand.GetAddrMode();
   1933     int32_t offset = operand.GetOffsetImmediate();
   1934     uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
   1935     // Try to maximize the offset used by the MemOperand (load_store_offset).
   1936     // Add the part which can't be used by the MemOperand (add_offset).
   1937     uint32_t load_store_offset = offset & extra_offset_mask;
   1938     uint32_t add_offset = offset & ~extra_offset_mask;
   1939     if ((add_offset != 0) &&
   1940         (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
   1941       load_store_offset = 0;
   1942       add_offset = offset;
   1943     }
   1944     switch (addrmode) {
   1945       case PreIndex: {
   1946         // Allow using the destinations as a scratch registers if possible.
   1947         UseScratchRegisterScope temps(this);
   1948         if (type == kLdrd) {
   1949           if (!rt.Is(rn)) temps.Include(rt);
   1950           if (!rt2.Is(rn)) temps.Include(rt2);
   1951         }
   1952 
   1953         // Pre-Indexed case:
   1954         // ldrd r0, r1, [r2, 12345]! will translate into
   1955         //   add r2, 12345
   1956         //   ldrd r0, r1, [r2]
   1957         {
   1958           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1959           add(cond, rn, rn, add_offset);
   1960         }
   1961         {
   1962           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1963           (this->*instruction)(cond,
   1964                                rt,
   1965                                rt2,
   1966                                MemOperand(rn, load_store_offset, PreIndex));
   1967         }
   1968         return;
   1969       }
   1970       case Offset: {
   1971         UseScratchRegisterScope temps(this);
   1972         // Allow using the destinations as a scratch registers if possible.
   1973         if (type == kLdrd) {
   1974           if (!rt.Is(rn)) temps.Include(rt);
   1975           if (!rt2.Is(rn)) temps.Include(rt2);
   1976         }
   1977         Register scratch = temps.Acquire();
   1978         // Offset case:
   1979         // ldrd r0, r1, [r2, 12345] will translate into
   1980         //   add r0, r2, 12345
   1981         //   ldrd r0, r1, [r0]
   1982         {
   1983           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   1984           add(cond, scratch, rn, add_offset);
   1985         }
   1986         {
   1987           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   1988           (this->*instruction)(cond,
   1989                                rt,
   1990                                rt2,
   1991                                MemOperand(scratch, load_store_offset));
   1992         }
   1993         return;
   1994       }
   1995       case PostIndex:
   1996         // Avoid the unpredictable case 'ldrd r0, r1, [r0], imm'
   1997         if (!rn.Is(rt) && !rn.Is(rt2)) {
   1998           // Post-indexed case:
   1999           // ldrd r0, r1, [r2], imm32 will translate into
   2000           //   ldrd r0, r1, [r2]
   2001           //   movw ip. imm32 & 0xffffffff
   2002           //   movt ip, imm32 >> 16
   2003           //   add r2, ip
   2004           {
   2005             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2006             (this->*instruction)(cond,
   2007                                  rt,
   2008                                  rt2,
   2009                                  MemOperand(rn, load_store_offset, PostIndex));
   2010           }
   2011           {
   2012             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2013             add(cond, rn, rn, add_offset);
   2014           }
   2015           return;
   2016         }
   2017         break;
   2018     }
   2019   }
   2020   if (operand.IsPlainRegister()) {
   2021     const Register& rn = operand.GetBaseRegister();
   2022     const Register& rm = operand.GetOffsetRegister();
   2023     AddrMode addrmode = operand.GetAddrMode();
   2024     switch (addrmode) {
   2025       case PreIndex:
   2026         // ldrd r0, r1, [r2, r3]! will translate into
   2027         //   add r2, r3
   2028         //   ldrd r0, r1, [r2]
   2029         {
   2030           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2031           if (operand.GetSign().IsPlus()) {
   2032             add(cond, rn, rn, rm);
   2033           } else {
   2034             sub(cond, rn, rn, rm);
   2035           }
   2036         }
   2037         {
   2038           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2039           (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
   2040         }
   2041         return;
   2042       case PostIndex:
   2043         // ldrd r0, r1, [r2], r3 will translate into
   2044         //   ldrd r0, r1, [r2]
   2045         //   add r2, r3
   2046         {
   2047           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2048           (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
   2049         }
   2050         {
   2051           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2052           if (operand.GetSign().IsPlus()) {
   2053             add(cond, rn, rn, rm);
   2054           } else {
   2055             sub(cond, rn, rn, rm);
   2056           }
   2057         }
   2058         return;
   2059       case Offset: {
   2060         UseScratchRegisterScope temps(this);
   2061         // Allow using the destinations as a scratch registers if possible.
   2062         if (type == kLdrd) {
   2063           if (!rt.Is(rn)) temps.Include(rt);
   2064           if (!rt2.Is(rn)) temps.Include(rt2);
   2065         }
   2066         Register scratch = temps.Acquire();
   2067         // Offset case:
   2068         // ldrd r0, r1, [r2, r3] will translate into
   2069         //   add r0, r2, r3
   2070         //   ldrd r0, r1, [r0]
   2071         {
   2072           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2073           if (operand.GetSign().IsPlus()) {
   2074             add(cond, scratch, rn, rm);
   2075           } else {
   2076             sub(cond, scratch, rn, rm);
   2077           }
   2078         }
   2079         {
   2080           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2081           (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
   2082         }
   2083         return;
   2084       }
   2085     }
   2086   }
   2087   Assembler::Delegate(type, instruction, cond, rt, rt2, operand);
   2088 }
   2089 
   2090 
   2091 void MacroAssembler::Delegate(InstructionType type,
   2092                               InstructionCondDtSMop instruction,
   2093                               Condition cond,
   2094                               DataType dt,
   2095                               SRegister rd,
   2096                               const MemOperand& operand) {
   2097   CONTEXT_SCOPE;
   2098   if (operand.IsImmediate()) {
   2099     const Register& rn = operand.GetBaseRegister();
   2100     AddrMode addrmode = operand.GetAddrMode();
   2101     int32_t offset = operand.GetOffsetImmediate();
   2102     VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
   2103                 ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
   2104     if (rn.IsPC()) {
   2105       VIXL_ABORT_WITH_MSG(
   2106           "The MacroAssembler does not convert vldr or vstr with a PC base "
   2107           "register.\n");
   2108     }
   2109     switch (addrmode) {
   2110       case PreIndex:
   2111         // Pre-Indexed case:
   2112         // vldr.32 s0, [r1, 12345]! will translate into
   2113         //   add r1, 12345
   2114         //   vldr.32 s0, [r1]
   2115         if (offset != 0) {
   2116           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2117           add(cond, rn, rn, offset);
   2118         }
   2119         {
   2120           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2121           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
   2122         }
   2123         return;
   2124       case Offset: {
   2125         UseScratchRegisterScope temps(this);
   2126         Register scratch = temps.Acquire();
   2127         // Offset case:
   2128         // vldr.32 s0, [r1, 12345] will translate into
   2129         //   add ip, r1, 12345
   2130         //   vldr.32 s0, [ip]
   2131         {
   2132           VIXL_ASSERT(offset != 0);
   2133           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2134           add(cond, scratch, rn, offset);
   2135         }
   2136         {
   2137           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2138           (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
   2139         }
   2140         return;
   2141       }
   2142       case PostIndex:
   2143         // Post-indexed case:
   2144         // vldr.32 s0, [r1], imm32 will translate into
   2145         //   vldr.32 s0, [r1]
   2146         //   movw ip. imm32 & 0xffffffff
   2147         //   movt ip, imm32 >> 16
   2148         //   add r1, ip
   2149         {
   2150           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2151           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
   2152         }
   2153         if (offset != 0) {
   2154           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2155           add(cond, rn, rn, offset);
   2156         }
   2157         return;
   2158     }
   2159   }
   2160   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
   2161 }
   2162 
   2163 
   2164 void MacroAssembler::Delegate(InstructionType type,
   2165                               InstructionCondDtDMop instruction,
   2166                               Condition cond,
   2167                               DataType dt,
   2168                               DRegister rd,
   2169                               const MemOperand& operand) {
   2170   CONTEXT_SCOPE;
   2171   if (operand.IsImmediate()) {
   2172     const Register& rn = operand.GetBaseRegister();
   2173     AddrMode addrmode = operand.GetAddrMode();
   2174     int32_t offset = operand.GetOffsetImmediate();
   2175     VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
   2176                 ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
   2177     if (rn.IsPC()) {
   2178       VIXL_ABORT_WITH_MSG(
   2179           "The MacroAssembler does not convert vldr or vstr with a PC base "
   2180           "register.\n");
   2181     }
   2182     switch (addrmode) {
   2183       case PreIndex:
   2184         // Pre-Indexed case:
   2185         // vldr.64 d0, [r1, 12345]! will translate into
   2186         //   add r1, 12345
   2187         //   vldr.64 d0, [r1]
   2188         if (offset != 0) {
   2189           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2190           add(cond, rn, rn, offset);
   2191         }
   2192         {
   2193           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2194           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
   2195         }
   2196         return;
   2197       case Offset: {
   2198         UseScratchRegisterScope temps(this);
   2199         Register scratch = temps.Acquire();
   2200         // Offset case:
   2201         // vldr.64 d0, [r1, 12345] will translate into
   2202         //   add ip, r1, 12345
   2203         //   vldr.32 s0, [ip]
   2204         {
   2205           VIXL_ASSERT(offset != 0);
   2206           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2207           add(cond, scratch, rn, offset);
   2208         }
   2209         {
   2210           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2211           (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
   2212         }
   2213         return;
   2214       }
   2215       case PostIndex:
   2216         // Post-indexed case:
   2217         // vldr.64 d0. [r1], imm32 will translate into
   2218         //   vldr.64 d0, [r1]
   2219         //   movw ip. imm32 & 0xffffffff
   2220         //   movt ip, imm32 >> 16
   2221         //   add r1, ip
   2222         {
   2223           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2224           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
   2225         }
   2226         if (offset != 0) {
   2227           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
   2228           add(cond, rn, rn, offset);
   2229         }
   2230         return;
   2231     }
   2232   }
   2233   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
   2234 }
   2235 
   2236 
   2237 void MacroAssembler::Delegate(InstructionType type,
   2238                               InstructionCondMsrOp instruction,
   2239                               Condition cond,
   2240                               MaskedSpecialRegister spec_reg,
   2241                               const Operand& operand) {
   2242   USE(type);
   2243   VIXL_ASSERT(type == kMsr);
   2244   if (operand.IsImmediate()) {
   2245     UseScratchRegisterScope temps(this);
   2246     Register scratch = temps.Acquire();
   2247     {
   2248       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
   2249       mov(cond, scratch, operand);
   2250     }
   2251     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
   2252     msr(cond, spec_reg, scratch);
   2253     return;
   2254   }
   2255   Assembler::Delegate(type, instruction, cond, spec_reg, operand);
   2256 }
   2257 
   2258 
   2259 void MacroAssembler::Delegate(InstructionType type,
   2260                               InstructionCondDtDL instruction,
   2261                               Condition cond,
   2262                               DataType dt,
   2263                               DRegister rd,
   2264                               Location* location) {
   2265   VIXL_ASSERT(type == kVldr);
   2266 
   2267   CONTEXT_SCOPE;
   2268 
   2269   if (location->IsBound()) {
   2270     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
   2271     UseScratchRegisterScope temps(this);
   2272     Register scratch = temps.Acquire();
   2273     uint32_t mask = GetOffsetMask(type, Offset);
   2274     vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
   2275     return;
   2276   }
   2277 
   2278   Assembler::Delegate(type, instruction, cond, dt, rd, location);
   2279 }
   2280 
   2281 
   2282 void MacroAssembler::Delegate(InstructionType type,
   2283                               InstructionCondDtSL instruction,
   2284                               Condition cond,
   2285                               DataType dt,
   2286                               SRegister rd,
   2287                               Location* location) {
   2288   VIXL_ASSERT(type == kVldr);
   2289 
   2290   CONTEXT_SCOPE;
   2291 
   2292   if (location->IsBound()) {
   2293     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
   2294     UseScratchRegisterScope temps(this);
   2295     Register scratch = temps.Acquire();
   2296     uint32_t mask = GetOffsetMask(type, Offset);
   2297     vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
   2298     return;
   2299   }
   2300 
   2301   Assembler::Delegate(type, instruction, cond, dt, rd, location);
   2302 }
   2303 
   2304 
   2305 #undef CONTEXT_SCOPE
   2306 #undef TOSTRING
   2307 #undef STRINGIFY
   2308 
   2309 // Start of generated code.
   2310 // End of generated code.
   2311 }  // namespace aarch32
   2312 }  // namespace vixl
   2313