Home | History | Annotate | Download | only in DartARM32
      1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 //
      5 // This is forked from Dart revision df52deea9f25690eb8b66c5995da92b70f7ac1fe
      6 // Please update the (git) revision if we merge changes from Dart.
      7 // https://code.google.com/p/dart/wiki/GettingTheSource
      8 
      9 #include "vm/globals.h"  // NOLINT
     10 #if defined(TARGET_ARCH_ARM)
     11 
     12 #include "vm/assembler.h"
     13 #include "vm/cpu.h"
     14 #include "vm/longjump.h"
     15 #include "vm/runtime_entry.h"
     16 #include "vm/simulator.h"
     17 #include "vm/stack_frame.h"
     18 #include "vm/stub_code.h"
     19 
     20 // An extra check since we are assuming the existence of /proc/cpuinfo below.
     21 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID)
     22 #error ARM cross-compile only supported on Linux
     23 #endif
     24 
     25 namespace dart {
     26 
     27 DECLARE_FLAG(bool, allow_absolute_addresses);
     28 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
     29 DECLARE_FLAG(bool, inline_alloc);
     30 
     31 #if 0
     32 // Moved to encodeImmRegOffsetEnc3 in IceAssemblerARM32.cpp
     33 uint32_t Address::encoding3() const {
     34   if (kind_ == Immediate) {
     35     uint32_t offset = encoding_ & kOffset12Mask;
     36     ASSERT(offset < 256);
     37     return (encoding_ & ~kOffset12Mask) | B22 |
     38            ((offset & 0xf0) << 4) | (offset & 0xf);
     39   }
     40   ASSERT(kind_ == IndexRegister);
     41   return encoding_;
     42 }
     43 #endif
     44 
     45 uint32_t Address::vencoding() const {
     46   ASSERT(kind_ == Immediate);
     47   uint32_t offset = encoding_ & kOffset12Mask;
     48   ASSERT(offset < (1 << 10));  // In the range 0 to +1020.
     49   ASSERT(Utils::IsAligned(offset, 4));  // Multiple of 4.
     50   int mode = encoding_ & ((8|4|1) << 21);
     51   ASSERT((mode == Offset) || (mode == NegOffset));
     52   uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2);
     53   if (mode == Offset) {
     54     vencoding |= 1 << 23;
     55   }
     56   return vencoding;
     57 }
     58 
     59 
     60 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
     61   ASSERT(Utils::IsAligned(data, 4));
     62   ASSERT(Utils::IsAligned(length, 4));
     63   const uword end = data + length;
     64   while (data < end) {
     65     *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction;
     66     data += 4;
     67   }
     68 }
     69 
     70 
     71 void Assembler::Emit(int32_t value) {
     72   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
     73   buffer_.Emit<int32_t>(value);
     74 }
     75 
     76 #if 0
     77 // Moved to ARM32::AssemblerARM32::emitType01()
     78 void Assembler::EmitType01(Condition cond,
     79                            int type,
     80                            Opcode opcode,
     81                            int set_cc,
     82                            Register rn,
     83                            Register rd,
     84                            Operand o) {
     85   ASSERT(rd != kNoRegister);
     86   ASSERT(cond != kNoCondition);
     87   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
     88                      type << kTypeShift |
     89                      static_cast<int32_t>(opcode) << kOpcodeShift |
     90                      set_cc << kSShift |
     91                      static_cast<int32_t>(rn) << kRnShift |
     92                      static_cast<int32_t>(rd) << kRdShift |
     93                      o.encoding();
     94   Emit(encoding);
     95 }
     96 
     97 // Moved to ARM32::AssemblerARM32::emitType05()
     98 void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
     99   ASSERT(cond != kNoCondition);
    100   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
    101                      5 << kTypeShift |
    102                      (link ? 1 : 0) << kLinkShift;
    103   Emit(Assembler::EncodeBranchOffset(offset, encoding));
    104 }
    105 
    106 // Moved to ARM32::AssemblerARM32::emitMemOp()
    107 void Assembler::EmitMemOp(Condition cond,
    108                           bool load,
    109                           bool byte,
    110                           Register rd,
    111                           Address ad) {
    112   ASSERT(rd != kNoRegister);
    113   ASSERT(cond != kNoCondition);
    114   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    115                      B26 | (ad.kind() == Address::Immediate ? 0 : B25) |
    116                      (load ? L : 0) |
    117                      (byte ? B : 0) |
    118                      (static_cast<int32_t>(rd) << kRdShift) |
    119                      ad.encoding();
    120   Emit(encoding);
    121 }
    122 
    123 // Moved to AssemblerARM32::emitMemOpEnc3();
    124 void Assembler::EmitMemOpAddressMode3(Condition cond,
    125                                       int32_t mode,
    126                                       Register rd,
    127                                       Address ad) {
    128   ASSERT(rd != kNoRegister);
    129   ASSERT(cond != kNoCondition);
    130   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    131                      mode |
    132                      (static_cast<int32_t>(rd) << kRdShift) |
    133                      ad.encoding3();
    134   Emit(encoding);
    135 }
    136 
    137 // Moved to ARM32::AssemblerARM32::emitMuliMemOp()
    138 void Assembler::EmitMultiMemOp(Condition cond,
    139                                BlockAddressMode am,
    140                                bool load,
    141                                Register base,
    142                                RegList regs) {
    143   ASSERT(base != kNoRegister);
    144   ASSERT(cond != kNoCondition);
    145   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    146                      B27 |
    147                      am |
    148                      (load ? L : 0) |
    149                      (static_cast<int32_t>(base) << kRnShift) |
    150                      regs;
    151   Emit(encoding);
    152 }
    153 #endif
    154 
    155 void Assembler::EmitShiftImmediate(Condition cond,
    156                                    Shift opcode,
    157                                    Register rd,
    158                                    Register rm,
    159                                    Operand o) {
    160   ASSERT(cond != kNoCondition);
    161   ASSERT(o.type() == 1);
    162   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
    163                      static_cast<int32_t>(MOV) << kOpcodeShift |
    164                      static_cast<int32_t>(rd) << kRdShift |
    165                      o.encoding() << kShiftImmShift |
    166                      static_cast<int32_t>(opcode) << kShiftShift |
    167                      static_cast<int32_t>(rm);
    168   Emit(encoding);
    169 }
    170 
    171 
    172 void Assembler::EmitShiftRegister(Condition cond,
    173                                   Shift opcode,
    174                                   Register rd,
    175                                   Register rm,
    176                                   Operand o) {
    177   ASSERT(cond != kNoCondition);
    178   ASSERT(o.type() == 0);
    179   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
    180                      static_cast<int32_t>(MOV) << kOpcodeShift |
    181                      static_cast<int32_t>(rd) << kRdShift |
    182                      o.encoding() << kShiftRegisterShift |
    183                      static_cast<int32_t>(opcode) << kShiftShift |
    184                      B4 |
    185                      static_cast<int32_t>(rm);
    186   Emit(encoding);
    187 }
    188 
    189 
    190 #if 0
    191 // Moved to ARM32::AssemblerARM32::and_()
    192 void Assembler::and_(Register rd, Register rn, Operand o, Condition cond) {
    193   EmitType01(cond, o.type(), AND, 0, rn, rd, o);
    194 }
    195 
    196 // Moved to ARM32::AssemberARM32::eor()
    197 void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) {
    198   EmitType01(cond, o.type(), EOR, 0, rn, rd, o);
    199 }
    200 
    201 // Moved to ARM32::AssemberARM32::sub()
    202 void Assembler::sub(Register rd, Register rn, Operand o, Condition cond) {
    203   EmitType01(cond, o.type(), SUB, 0, rn, rd, o);
    204 }
    205 
    206 // Moved to ARM32::AssemberARM32::rsb()
    207 void Assembler::rsb(Register rd, Register rn, Operand o, Condition cond) {
    208   EmitType01(cond, o.type(), RSB, 0, rn, rd, o);
    209 }
    210 
    211 // Moved to ARM32::AssemberARM32::rsb()
    212 void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
    213   EmitType01(cond, o.type(), RSB, 1, rn, rd, o);
    214 }
    215 
    216 // Moved to ARM32::AssemberARM32::add()
    217 void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
    218   EmitType01(cond, o.type(), ADD, 0, rn, rd, o);
    219 }
    220 
    221 // Moved to ARM32::AssemberARM32::add()
    222 void Assembler::adds(Register rd, Register rn, Operand o, Condition cond) {
    223   EmitType01(cond, o.type(), ADD, 1, rn, rd, o);
    224 }
    225 
    226 // Moved to ARM32::AssemberARM32::sub()
    227 void Assembler::subs(Register rd, Register rn, Operand o, Condition cond) {
    228   EmitType01(cond, o.type(), SUB, 1, rn, rd, o);
    229 }
    230 
    231 // Moved to ARM32::AssemberARM32::adc()
    232 void Assembler::adc(Register rd, Register rn, Operand o, Condition cond) {
    233   EmitType01(cond, o.type(), ADC, 0, rn, rd, o);
    234 }
    235 
    236 // Moved to ARM32::AssemberARM32::adc()
    237 void Assembler::adcs(Register rd, Register rn, Operand o, Condition cond) {
    238   EmitType01(cond, o.type(), ADC, 1, rn, rd, o);
    239 }
    240 #endif
    241 
    242 void Assembler::sbc(Register rd, Register rn, Operand o, Condition cond) {
    243   EmitType01(cond, o.type(), SBC, 0, rn, rd, o);
    244 }
    245 
    246 
    247 void Assembler::sbcs(Register rd, Register rn, Operand o, Condition cond) {
    248   EmitType01(cond, o.type(), SBC, 1, rn, rd, o);
    249 }
    250 
    251 #if 0
    252 // Moved to ARM32::AssemblerARM32::rsc()f
    253 void Assembler::rsc(Register rd, Register rn, Operand o, Condition cond) {
    254   EmitType01(cond, o.type(), RSC, 0, rn, rd, o);
    255 }
    256 
    257 // Moved to ARM32::AssemblerARM32::tst()
    258 void Assembler::tst(Register rn, Operand o, Condition cond) {
    259   EmitType01(cond, o.type(), TST, 1, rn, R0, o);
    260 }
    261 #endif
    262 
    263 void Assembler::teq(Register rn, Operand o, Condition cond) {
    264   EmitType01(cond, o.type(), TEQ, 1, rn, R0, o);
    265 }
    266 
    267 #if 0
    268 // Moved to ARM32::AssemblerARM32::cmp()
    269 void Assembler::cmp(Register rn, Operand o, Condition cond) {
    270   EmitType01(cond, o.type(), CMP, 1, rn, R0, o);
    271 }
    272 
    273 // Moved to ARM32::AssemblerARM32::cmn()
    274 void Assembler::cmn(Register rn, Operand o, Condition cond) {
    275   EmitType01(cond, o.type(), CMN, 1, rn, R0, o);
    276 }
    277 
    278 // Moved to ARM32::AssemberARM32::orr()
    279 void Assembler::orr(Register rd, Register rn, Operand o, Condition cond) {
    280   EmitType01(cond, o.type(), ORR, 0, rn, rd, o);
    281 }
    282 
    283 // Moved to ARM32::AssemberARM32::orr()
    284 void Assembler::orrs(Register rd, Register rn, Operand o, Condition cond) {
    285   EmitType01(cond, o.type(), ORR, 1, rn, rd, o);
    286 }
    287 
    288 // Moved to ARM32::AssemblerARM32::mov()
    289 // TODO(kschimpf) other forms of move.
    290 void Assembler::mov(Register rd, Operand o, Condition cond) {
    291   EmitType01(cond, o.type(), MOV, 0, R0, rd, o);
    292 }
    293 #endif
    294 
    295 void Assembler::movs(Register rd, Operand o, Condition cond) {
    296   EmitType01(cond, o.type(), MOV, 1, R0, rd, o);
    297 }
    298 
    299 
    300 #if 0
    301 // Moved to ARM32::AssemblerARM32::bic()
    302 void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) {
    303   EmitType01(cond, o.type(), BIC, 0, rn, rd, o);
    304 }
    305 
    306 // Moved to ARM32::AssemblerARM32::bic()
    307 void Assembler::bics(Register rd, Register rn, Operand o, Condition cond) {
    308   EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
    309 }
    310 
    311 // Moved to ARM32::AssemblerARM32::mvn()
    312 void Assembler::mvn(Register rd, Operand o, Condition cond) {
    313   EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
    314 }
    315 
    316 // Moved to ARM32::AssemblerARM32::mvn()
    317 void Assembler::mvns(Register rd, Operand o, Condition cond) {
    318   EmitType01(cond, o.type(), MVN, 1, R0, rd, o);
    319 }
    320 
    321 // Moved to ARM32::AssemblerARM32::clz()
    322 void Assembler::clz(Register rd, Register rm, Condition cond) {
    323   ASSERT(rd != kNoRegister);
    324   ASSERT(rm != kNoRegister);
    325   ASSERT(cond != kNoCondition);
    326   ASSERT(rd != PC);
    327   ASSERT(rm != PC);
    328   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    329                      B24 | B22 | B21 | (0xf << 16) |
    330                      (static_cast<int32_t>(rd) << kRdShift) |
    331                      (0xf << 8) | B4 | static_cast<int32_t>(rm);
    332   Emit(encoding);
    333 }
    334 
    335 // Moved to ARM32::AssemblerARM32::movw()
    336 void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
    337   ASSERT(cond != kNoCondition);
    338   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
    339                      B25 | B24 | ((imm16 >> 12) << 16) |
    340                      static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
    341   Emit(encoding);
    342 }
    343 
    344 
    345 // Moved to ARM32::AssemblerARM32::movt()
    346 void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
    347   ASSERT(cond != kNoCondition);
    348   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
    349                      B25 | B24 | B22 | ((imm16 >> 12) << 16) |
    350                      static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
    351   Emit(encoding);
    352 }
    353 
    354 // Moved to ARM32::AssemblerARM32::emitMulOp()
    355 void Assembler::EmitMulOp(Condition cond, int32_t opcode,
    356                           Register rd, Register rn,
    357                           Register rm, Register rs) {
    358   ASSERT(rd != kNoRegister);
    359   ASSERT(rn != kNoRegister);
    360   ASSERT(rm != kNoRegister);
    361   ASSERT(rs != kNoRegister);
    362   ASSERT(cond != kNoCondition);
    363   int32_t encoding = opcode |
    364       (static_cast<int32_t>(cond) << kConditionShift) |
    365       (static_cast<int32_t>(rn) << kRnShift) |
    366       (static_cast<int32_t>(rd) << kRdShift) |
    367       (static_cast<int32_t>(rs) << kRsShift) |
    368       B7 | B4 |
    369       (static_cast<int32_t>(rm) << kRmShift);
    370   Emit(encoding);
    371 }
    372 
    373 // Moved to ARM32::AssemblerARM32::mul()
    374 void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
    375   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
    376   EmitMulOp(cond, 0, R0, rd, rn, rm);
    377 }
    378 #endif
    379 
    380 // Like mul, but sets condition flags.
    381 void Assembler::muls(Register rd, Register rn, Register rm, Condition cond) {
    382   EmitMulOp(cond, B20, R0, rd, rn, rm);
    383 }
    384 
    385 #if 0
    386 // Moved to ARM32::AssemblerARM32::mla()
    387 void Assembler::mla(Register rd, Register rn,
    388                     Register rm, Register ra, Condition cond) {
    389   // rd <- ra + rn * rm.
    390   // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
    391   EmitMulOp(cond, B21, ra, rd, rn, rm);
    392 }
    393 
    394 // Moved to ARM32::AssemblerARM32::mla()
    395 void Assembler::mls(Register rd, Register rn,
    396                     Register rm, Register ra, Condition cond) {
    397   // rd <- ra - rn * rm.
    398   if (TargetCPUFeatures::arm_version() == ARMv7) {
    399     // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
    400     EmitMulOp(cond, B22 | B21, ra, rd, rn, rm);
    401   } else {
    402     mul(IP, rn, rm, cond);
    403     sub(rd, ra, Operand(IP), cond);
    404   }
    405 }
    406 #endif
    407 
    408 void Assembler::smull(Register rd_lo, Register rd_hi,
    409                       Register rn, Register rm, Condition cond) {
    410   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
    411   EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
    412 }
    413 
    414 #if 0
    415 // Moved to ARM32::AssemblerARM32::umull()
    416 void Assembler::umull(Register rd_lo, Register rd_hi,
    417                       Register rn, Register rm, Condition cond) {
    418   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
    419   EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm);
    420 }
    421 #endif
    422 
    423 void Assembler::umlal(Register rd_lo, Register rd_hi,
    424                       Register rn, Register rm, Condition cond) {
    425   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
    426   EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm);
    427 }
    428 
    429 
    430 void Assembler::umaal(Register rd_lo, Register rd_hi,
    431                       Register rn, Register rm) {
    432   ASSERT(rd_lo != IP);
    433   ASSERT(rd_hi != IP);
    434   ASSERT(rn != IP);
    435   ASSERT(rm != IP);
    436   if (TargetCPUFeatures::arm_version() != ARMv5TE) {
    437     // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
    438     EmitMulOp(AL, B22, rd_lo, rd_hi, rn, rm);
    439   } else {
    440     mov(IP, Operand(0));
    441     umlal(rd_lo, IP, rn, rm);
    442     adds(rd_lo, rd_lo, Operand(rd_hi));
    443     adc(rd_hi, IP, Operand(0));
    444   }
    445 }
    446 
    447 
    448 #if 0
    449 // Moved to ARM32::AssemblerARM32::emitDivOp()
    450 void Assembler::EmitDivOp(Condition cond, int32_t opcode,
    451                           Register rd, Register rn, Register rm) {
    452   ASSERT(TargetCPUFeatures::integer_division_supported());
    453   ASSERT(rd != kNoRegister);
    454   ASSERT(rn != kNoRegister);
    455   ASSERT(rm != kNoRegister);
    456   ASSERT(cond != kNoCondition);
    457   int32_t encoding = opcode |
    458     (static_cast<int32_t>(cond) << kConditionShift) |
    459     (static_cast<int32_t>(rn) << kDivRnShift) |
    460     (static_cast<int32_t>(rd) << kDivRdShift) |
    461       // TODO(kschimpf): Why not also: B15 | B14 | B13 | B12?
    462     B26 | B25 | B24 | B20 | B4 |
    463     (static_cast<int32_t>(rm) << kDivRmShift);
    464   Emit(encoding);
    465 }
    466 
    467 // Moved to ARM32::AssemblerARM32::sdiv()
    468 void Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
    469   EmitDivOp(cond, 0, rd, rn, rm);
    470 }
    471 
    472 // Moved to ARM32::AssemblerARM32::udiv()
    473 void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
    474   EmitDivOp(cond, B21 , rd, rn, rm);
    475 }
    476 
    477 // Moved to ARM32::AssemblerARM32::ldr()
    478 void Assembler::ldr(Register rd, Address ad, Condition cond) {
    479   EmitMemOp(cond, true, false, rd, ad);
    480 }
    481 
    482 // Moved to ARM32::AssemblerARM32::str()
    483 void Assembler::str(Register rd, Address ad, Condition cond) {
    484   EmitMemOp(cond, false, false, rd, ad);
    485 }
    486 
    487 // Moved to ARM32::AssemblerARM32::ldr()
    488 void Assembler::ldrb(Register rd, Address ad, Condition cond) {
    489   EmitMemOp(cond, true, true, rd, ad);
    490 }
    491 
    492 // Moved to ARM32::AssemblerARM32::str()
    493 void Assembler::strb(Register rd, Address ad, Condition cond) {
    494   EmitMemOp(cond, false, true, rd, ad);
    495 }
    496 #endif
    497 
    498 void Assembler::ldrh(Register rd, Address ad, Condition cond) {
    499   EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad);
    500 }
    501 
    502 
    503 void Assembler::strh(Register rd, Address ad, Condition cond) {
    504   EmitMemOpAddressMode3(cond, B7 | H | B4, rd, ad);
    505 }
    506 
    507 
    508 void Assembler::ldrsb(Register rd, Address ad, Condition cond) {
    509   EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad);
    510 }
    511 
    512 
    513 void Assembler::ldrsh(Register rd, Address ad, Condition cond) {
    514   EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad);
    515 }
    516 
    517 
    518 void Assembler::ldrd(Register rd, Register rn, int32_t offset, Condition cond) {
    519   ASSERT((rd % 2) == 0);
    520   if (TargetCPUFeatures::arm_version() == ARMv5TE) {
    521     const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
    522     ldr(rd, Address(rn, offset), cond);
    523     ldr(rd2, Address(rn, offset + kWordSize), cond);
    524   } else {
    525     EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, Address(rn, offset));
    526   }
    527 }
    528 
    529 
    530 void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) {
    531   ASSERT((rd % 2) == 0);
    532   if (TargetCPUFeatures::arm_version() == ARMv5TE) {
    533     const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
    534     str(rd, Address(rn, offset), cond);
    535     str(rd2, Address(rn, offset + kWordSize), cond);
    536   } else {
    537     EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, Address(rn, offset));
    538   }
    539 }
    540 
    541 #if 0
    542 // Folded into ARM32::AssemblerARM32::popList(), since it is its only
    543 // use (and doesn't implement ARM STM instruction).
    544 void Assembler::ldm(BlockAddressMode am, Register base, RegList regs,
    545                     Condition cond) {
    546   ASSERT(regs != 0);
    547   EmitMultiMemOp(cond, am, true, base, regs);
    548 }
    549 
    550 // Folded into ARM32::AssemblerARM32::pushList(), since it is its only
    551 // use (and doesn't implement ARM STM instruction).
    552 void Assembler::stm(BlockAddressMode am, Register base, RegList regs,
    553                     Condition cond) {
    554   ASSERT(regs != 0);
    555   EmitMultiMemOp(cond, am, false, base, regs);
    556 }
    557 
    558 // Moved to ARM::AssemblerARM32::ldrex();
    559 void Assembler::ldrex(Register rt, Register rn, Condition cond) {
    560   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
    561   ASSERT(rn != kNoRegister);
    562   ASSERT(rt != kNoRegister);
    563   ASSERT(cond != kNoCondition);
    564   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    565                      B24 |
    566                      B23 |
    567                      L   |
    568                      (static_cast<int32_t>(rn) << kLdExRnShift) |
    569                      (static_cast<int32_t>(rt) << kLdExRtShift) |
    570                      B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0;
    571   Emit(encoding);
    572 }
    573 
    574 // Moved to ARM::AssemblerARM32::strex();
    575 void Assembler::strex(Register rd, Register rt, Register rn, Condition cond) {
    576   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
    577   ASSERT(rn != kNoRegister);
    578   ASSERT(rd != kNoRegister);
    579   ASSERT(rt != kNoRegister);
    580   ASSERT(cond != kNoCondition);
    581   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    582                      B24 |
    583                      B23 |
    584                      (static_cast<int32_t>(rn) << kStrExRnShift) |
    585                      (static_cast<int32_t>(rd) << kStrExRdShift) |
    586                      B11 | B10 | B9 | B8 | B7 | B4 |
    587                      (static_cast<int32_t>(rt) << kStrExRtShift);
    588   Emit(encoding);
    589 }
    590 #endif
    591 
    592 void Assembler::clrex() {
    593   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
    594   int32_t encoding = (kSpecialCondition << kConditionShift) |
    595                      B26 | B24 | B22 | B21 | B20 | (0xff << 12) | B4 | 0xf;
    596   Emit(encoding);
    597 }
    598 
    599 #if 0
    600 // Moved to ARM32::AssemblerARM32::nop().
    601 void Assembler::nop(Condition cond) {
    602   ASSERT(cond != kNoCondition);
    603   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    604                      B25 | B24 | B21 | (0xf << 12);
    605   Emit(encoding);
    606 }
    607 
    608 // Moved to ARM32::AssemblerARM32::vmovsr().
    609 void Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
    610   ASSERT(TargetCPUFeatures::vfp_supported());
    611   ASSERT(sn != kNoSRegister);
    612   ASSERT(rt != kNoRegister);
    613   ASSERT(rt != SP);
    614   ASSERT(rt != PC);
    615   ASSERT(cond != kNoCondition);
    616   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    617                      B27 | B26 | B25 |
    618                      ((static_cast<int32_t>(sn) >> 1)*B16) |
    619                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
    620                      ((static_cast<int32_t>(sn) & 1)*B7) | B4;
    621   Emit(encoding);
    622 }
    623 
    624 // Moved to ARM32::AssemblerARM32::vmovrs().
    625 void Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
    626   ASSERT(TargetCPUFeatures::vfp_supported());
    627   ASSERT(sn != kNoSRegister);
    628   ASSERT(rt != kNoRegister);
    629   ASSERT(rt != SP);
    630   ASSERT(rt != PC);
    631   ASSERT(cond != kNoCondition);
    632   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    633                      B27 | B26 | B25 | B20 |
    634                      ((static_cast<int32_t>(sn) >> 1)*B16) |
    635                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
    636                      ((static_cast<int32_t>(sn) & 1)*B7) | B4;
    637   Emit(encoding);
    638 }
    639 #endif
    640 
    641 
    642 void Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
    643                         Condition cond) {
    644   ASSERT(TargetCPUFeatures::vfp_supported());
    645   ASSERT(sm != kNoSRegister);
    646   ASSERT(sm != S31);
    647   ASSERT(rt != kNoRegister);
    648   ASSERT(rt != SP);
    649   ASSERT(rt != PC);
    650   ASSERT(rt2 != kNoRegister);
    651   ASSERT(rt2 != SP);
    652   ASSERT(rt2 != PC);
    653   ASSERT(cond != kNoCondition);
    654   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    655                      B27 | B26 | B22 |
    656                      (static_cast<int32_t>(rt2)*B16) |
    657                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
    658                      ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
    659                      (static_cast<int32_t>(sm) >> 1);
    660   Emit(encoding);
    661 }
    662 
    663 
    664 void Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
    665                         Condition cond) {
    666   ASSERT(TargetCPUFeatures::vfp_supported());
    667   ASSERT(sm != kNoSRegister);
    668   ASSERT(sm != S31);
    669   ASSERT(rt != kNoRegister);
    670   ASSERT(rt != SP);
    671   ASSERT(rt != PC);
    672   ASSERT(rt2 != kNoRegister);
    673   ASSERT(rt2 != SP);
    674   ASSERT(rt2 != PC);
    675   ASSERT(rt != rt2);
    676   ASSERT(cond != kNoCondition);
    677   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    678                      B27 | B26 | B22 | B20 |
    679                      (static_cast<int32_t>(rt2)*B16) |
    680                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
    681                      ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
    682                      (static_cast<int32_t>(sm) >> 1);
    683   Emit(encoding);
    684 }
    685 
    686 #if 0
    687 // Moved to ARM32::AssemblerARM32::vmovdqir().
    688 void Assembler::vmovdr(DRegister dn, int i, Register rt, Condition cond) {
    689   ASSERT(TargetCPUFeatures::vfp_supported());
    690   ASSERT((i == 0) || (i == 1));
    691   ASSERT(rt != kNoRegister);
    692   ASSERT(rt != SP);
    693   ASSERT(rt != PC);
    694   ASSERT(dn != kNoDRegister);
    695   ASSERT(cond != kNoCondition);
    696   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    697                      B27 | B26 | B25 |
    698                      (i*B21) |
    699                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
    700                      ((static_cast<int32_t>(dn) >> 4)*B7) |
    701                      ((static_cast<int32_t>(dn) & 0xf)*B16) | B4;
    702   Emit(encoding);
    703 }
    704 
    705 // Moved to ARM32::AssemblerARM32::vmovdrr().
    706 void Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
    707                         Condition cond) {
    708   ASSERT(TargetCPUFeatures::vfp_supported());
    709   ASSERT(dm != kNoDRegister);
    710   ASSERT(rt != kNoRegister);
    711   ASSERT(rt != SP);
    712   ASSERT(rt != PC);
    713   ASSERT(rt2 != kNoRegister);
    714   ASSERT(rt2 != SP);
    715   ASSERT(rt2 != PC);
    716   ASSERT(cond != kNoCondition);
    717   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    718                      B27 | B26 | B22 |
    719                      (static_cast<int32_t>(rt2)*B16) |
    720                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
    721                      ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
    722                      (static_cast<int32_t>(dm) & 0xf);
    723   Emit(encoding);
    724 }
    725 
    726 // Moved to ARM32::AssemblerARM32::vmovrrd().
    727 void Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
    728                         Condition cond) {
    729   ASSERT(TargetCPUFeatures::vfp_supported());
    730   ASSERT(dm != kNoDRegister);
    731   ASSERT(rt != kNoRegister);
    732   ASSERT(rt != SP);
    733   ASSERT(rt != PC);
    734   ASSERT(rt2 != kNoRegister);
    735   ASSERT(rt2 != SP);
    736   ASSERT(rt2 != PC);
    737   ASSERT(rt != rt2);
    738   ASSERT(cond != kNoCondition);
    739   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    740                      B27 | B26 | B22 | B20 |
    741                      (static_cast<int32_t>(rt2)*B16) |
    742                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
    743                      ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
    744                      (static_cast<int32_t>(dm) & 0xf);
    745   Emit(encoding);
    746 }
    747 
    748 // Moved to ARM32::AssemblerARM32::vldrs()
    749 void Assembler::vldrs(SRegister sd, Address ad, Condition cond) {
    750   ASSERT(TargetCPUFeatures::vfp_supported());
    751   ASSERT(sd != kNoSRegister);
    752   ASSERT(cond != kNoCondition);
    753   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    754                      B27 | B26 | B24 | B20 |
    755                      ((static_cast<int32_t>(sd) & 1)*B22) |
    756                      ((static_cast<int32_t>(sd) >> 1)*B12) |
    757                      B11 | B9 | ad.vencoding();
    758   Emit(encoding);
    759 }
    760 
    761 // Moved to Arm32::AssemblerARM32::vstrs()
    762 void Assembler::vstrs(SRegister sd, Address ad, Condition cond) {
    763   ASSERT(TargetCPUFeatures::vfp_supported());
    764   ASSERT(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)) != PC);
    765   ASSERT(sd != kNoSRegister);
    766   ASSERT(cond != kNoCondition);
    767   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    768                      B27 | B26 | B24 |
    769                      ((static_cast<int32_t>(sd) & 1)*B22) |
    770                      ((static_cast<int32_t>(sd) >> 1)*B12) |
    771                      B11 | B9 | ad.vencoding();
    772   Emit(encoding);
    773 }
    774 
    775 void Assembler::vldrd(DRegister dd, Address ad, Condition cond) {
    776   ASSERT(TargetCPUFeatures::vfp_supported());
    777   ASSERT(dd != kNoDRegister);
    778   ASSERT(cond != kNoCondition);
    779   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    780                      B27 | B26 | B24 | B20 |
    781                      ((static_cast<int32_t>(dd) >> 4)*B22) |
    782                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
    783                      B11 | B9 | B8 | ad.vencoding();
    784   Emit(encoding);
    785 }
    786 #endif
    787 
    788 void Assembler::vstrd(DRegister dd, Address ad, Condition cond) {
    789   ASSERT(TargetCPUFeatures::vfp_supported());
    790   ASSERT(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)) != PC);
    791   ASSERT(dd != kNoDRegister);
    792   ASSERT(cond != kNoCondition);
    793   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    794                      B27 | B26 | B24 |
    795                      ((static_cast<int32_t>(dd) >> 4)*B22) |
    796                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
    797                      B11 | B9 | B8 | ad.vencoding();
    798   Emit(encoding);
    799 }
    800 
    801 void Assembler::EmitMultiVSMemOp(Condition cond,
    802                                 BlockAddressMode am,
    803                                 bool load,
    804                                 Register base,
    805                                 SRegister start,
    806                                 uint32_t count) {
    807   ASSERT(TargetCPUFeatures::vfp_supported());
    808   ASSERT(base != kNoRegister);
    809   ASSERT(cond != kNoCondition);
    810   ASSERT(start != kNoSRegister);
    811   ASSERT(static_cast<int32_t>(start) + count <= kNumberOfSRegisters);
    812 
    813   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    814                      B27 | B26 | B11 | B9 |
    815                      am |
    816                      (load ? L : 0) |
    817                      (static_cast<int32_t>(base) << kRnShift) |
    818                      ((static_cast<int32_t>(start) & 0x1) ? D : 0) |
    819                      ((static_cast<int32_t>(start) >> 1) << 12) |
    820                      count;
    821   Emit(encoding);
    822 }
    823 
    824 
    825 void Assembler::EmitMultiVDMemOp(Condition cond,
    826                                 BlockAddressMode am,
    827                                 bool load,
    828                                 Register base,
    829                                 DRegister start,
    830                                 int32_t count) {
    831   ASSERT(TargetCPUFeatures::vfp_supported());
    832   ASSERT(base != kNoRegister);
    833   ASSERT(cond != kNoCondition);
    834   ASSERT(start != kNoDRegister);
    835   ASSERT(static_cast<int32_t>(start) + count <= kNumberOfDRegisters);
    836   const int armv5te = TargetCPUFeatures::arm_version() == ARMv5TE ? 1 : 0;
    837 
    838   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    839                      B27 | B26 | B11 | B9 | B8 |
    840                      am |
    841                      (load ? L : 0) |
    842                      (static_cast<int32_t>(base) << kRnShift) |
    843                      ((static_cast<int32_t>(start) & 0x10) ? D : 0) |
    844                      ((static_cast<int32_t>(start) & 0xf) << 12) |
    845                      (count << 1) | armv5te;
    846   Emit(encoding);
    847 }
    848 
    849 
    850 void Assembler::vldms(BlockAddressMode am, Register base,
    851                       SRegister first, SRegister last, Condition cond) {
    852   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
    853   ASSERT(last > first);
    854   EmitMultiVSMemOp(cond, am, true, base, first, last - first + 1);
    855 }
    856 
    857 
    858 void Assembler::vstms(BlockAddressMode am, Register base,
    859                       SRegister first, SRegister last, Condition cond) {
    860   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
    861   ASSERT(last > first);
    862   EmitMultiVSMemOp(cond, am, false, base, first, last - first + 1);
    863 }
    864 
    865 
    866 void Assembler::vldmd(BlockAddressMode am, Register base,
    867                       DRegister first, intptr_t count, Condition cond) {
    868   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
    869   ASSERT(count <= 16);
    870   ASSERT(first + count <= kNumberOfDRegisters);
    871   EmitMultiVDMemOp(cond, am, true, base, first, count);
    872 }
    873 
    874 
    875 void Assembler::vstmd(BlockAddressMode am, Register base,
    876                       DRegister first, intptr_t count, Condition cond) {
    877   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
    878   ASSERT(count <= 16);
    879   ASSERT(first + count <= kNumberOfDRegisters);
    880   EmitMultiVDMemOp(cond, am, false, base, first, count);
    881 }
    882 
    883 #if 0
    884 // Moved to ARM32::AssemblerARM32::emitVFPsss
    885 void Assembler::EmitVFPsss(Condition cond, int32_t opcode,
    886                            SRegister sd, SRegister sn, SRegister sm) {
    887   ASSERT(TargetCPUFeatures::vfp_supported());
    888   ASSERT(sd != kNoSRegister);
    889   ASSERT(sn != kNoSRegister);
    890   ASSERT(sm != kNoSRegister);
    891   ASSERT(cond != kNoCondition);
    892   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    893                      B27 | B26 | B25 | B11 | B9 | opcode |
    894                      ((static_cast<int32_t>(sd) & 1)*B22) |
    895                      ((static_cast<int32_t>(sn) >> 1)*B16) |
    896                      ((static_cast<int32_t>(sd) >> 1)*B12) |
    897                      ((static_cast<int32_t>(sn) & 1)*B7) |
    898                      ((static_cast<int32_t>(sm) & 1)*B5) |
    899                      (static_cast<int32_t>(sm) >> 1);
    900   Emit(encoding);
    901 }
    902 
    903 // Moved to ARM32::AssemblerARM32::emitVFPddd
    904 void Assembler::EmitVFPddd(Condition cond, int32_t opcode,
    905                            DRegister dd, DRegister dn, DRegister dm) {
    906   ASSERT(TargetCPUFeatures::vfp_supported());
    907   ASSERT(dd != kNoDRegister);
    908   ASSERT(dn != kNoDRegister);
    909   ASSERT(dm != kNoDRegister);
    910   ASSERT(cond != kNoCondition);
    911   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
    912                      B27 | B26 | B25 | B11 | B9 | B8 | opcode |
    913                      ((static_cast<int32_t>(dd) >> 4)*B22) |
    914                      ((static_cast<int32_t>(dn) & 0xf)*B16) |
    915                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
    916                      ((static_cast<int32_t>(dn) >> 4)*B7) |
    917                      ((static_cast<int32_t>(dm) >> 4)*B5) |
    918                      (static_cast<int32_t>(dm) & 0xf);
    919   Emit(encoding);
    920 }
    921 
    922 // Moved to Arm32::AssemblerARM32::vmovss()
    923 void Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
    924   EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
    925 }
    926 
    927 // Moved to Arm32::AssemblerARM32::vmovdd()
    928 void Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
    929   EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
    930 }
    931 
    932 // Moved to Arm32::AssemblerARM32::vmovs()
    933 bool Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
    934   if (TargetCPUFeatures::arm_version() != ARMv7) {
    935     return false;
    936   }
    937   uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
    938   if (((imm32 & ((1 << 19) - 1)) == 0) &&
    939       ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
    940        (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
    941     uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
    942         ((imm32 >> 19) & ((1 << 6) -1));
    943     EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
    944                sd, S0, S0);
    945     return true;
    946   }
    947   return false;
    948 }
    949 
    950 // Moved to Arm32::AssemblerARM32::vmovd()
    951 bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
    952   if (TargetCPUFeatures::arm_version() != ARMv7) {
    953     return false;
    954   }
    955   uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
    956   if (((imm64 & ((1LL << 48) - 1)) == 0) &&
    957       ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
    958        (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
    959     uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
    960         ((imm64 >> 48) & ((1 << 6) -1));
    961     EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
    962                dd, D0, D0);
    963     return true;
    964   }
    965   return false;
    966 }
    967 
    968 // Moved to Arm32::AssemblerARM32::vadds()
    969 void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
    970                       Condition cond) {
    971   EmitVFPsss(cond, B21 | B20, sd, sn, sm);
    972 }
    973 
    974 // Moved to Arm32::AssemblerARM32::vaddd()
    975 void Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
    976                       Condition cond) {
    977   EmitVFPddd(cond, B21 | B20, dd, dn, dm);
    978 }
    979 
    980 // Moved to Arm32::AssemblerARM32::vsubs()
    981 void Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
    982                       Condition cond) {
    983   EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
    984 }
    985 
    986 // Moved to Arm32::AssemblerARM32::vsubd()
    987 void Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
    988                       Condition cond) {
    989   EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
    990 }
    991 
    992 // Moved to Arm32::AssemblerARM32::vmuls()
    993 void Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
    994                       Condition cond) {
    995   EmitVFPsss(cond, B21, sd, sn, sm);
    996 }
    997 
    998 // Moved to Arm32::AssemblerARM32::vmuld()
    999 void Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
   1000                       Condition cond) {
   1001   EmitVFPddd(cond, B21, dd, dn, dm);
   1002 }
   1003 
   1004 // Moved to Arm32::AssemblerARM32::vmlas()
   1005 void Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
   1006                       Condition cond) {
   1007   EmitVFPsss(cond, 0, sd, sn, sm);
   1008 }
   1009 
   1010 // Moved to Arm32::AssemblerARM32::vmlad()
   1011 void Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
   1012                       Condition cond) {
   1013   EmitVFPddd(cond, 0, dd, dn, dm);
   1014 }
   1015 
   1016 // Moved to Arm32::AssemblerARM32::vmlss()
   1017 void Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
   1018                       Condition cond) {
   1019   EmitVFPsss(cond, B6, sd, sn, sm);
   1020 }
   1021 
   1022 // Moved to Arm32::AssemblerARM32::vmlsd()
   1023 void Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
   1024                       Condition cond) {
   1025   EmitVFPddd(cond, B6, dd, dn, dm);
   1026 }
   1027 
   1028 // Moved to Arm32::AssemblerARM32::vdivs()
   1029 void Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
   1030                       Condition cond) {
   1031   EmitVFPsss(cond, B23, sd, sn, sm);
   1032 }
   1033 
   1034 // Moved to Arm32::AssemblerARM32::vdivd()
   1035 void Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
   1036                       Condition cond) {
   1037   EmitVFPddd(cond, B23, dd, dn, dm);
   1038 }
   1039 
   1040 // Moved to Arm32::AssemblerARM32::vabss().
   1041 void Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
   1042   EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
   1043 }
   1044 
   1045 // Moved to Arm32::AssemblerARM32::vabsd().
   1046 void Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
   1047   EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
   1048 }
   1049 #endif
   1050 
   1051 void Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
   1052   EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
   1053 }
   1054 
   1055 
   1056 void Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
   1057   EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
   1058 }
   1059 
   1060 #if 0
   1061 // Moved to ARM32::AssemblerARM32::vsqrts().
   1062 void Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
   1063   EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
   1064 }
   1065 
   1066 // Moved to ARM32::AssemblerARM32::vsqrtd().
   1067 void Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
   1068   EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
   1069 }
   1070 
   1071 // Moved to ARM32::AssemblerARM32::emitVFPsd
   1072 void Assembler::EmitVFPsd(Condition cond, int32_t opcode,
   1073                           SRegister sd, DRegister dm) {
   1074   ASSERT(TargetCPUFeatures::vfp_supported());
   1075   ASSERT(sd != kNoSRegister);
   1076   ASSERT(dm != kNoDRegister);
   1077   ASSERT(cond != kNoCondition);
   1078   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
   1079                      B27 | B26 | B25 | B11 | B9 | opcode |
   1080                      ((static_cast<int32_t>(sd) & 1)*B22) |
   1081                      ((static_cast<int32_t>(sd) >> 1)*B12) |
   1082                      ((static_cast<int32_t>(dm) >> 4)*B5) |
   1083                      (static_cast<int32_t>(dm) & 0xf);
   1084   Emit(encoding);
   1085 }
   1086 
   1087 // Moved to ARM32::AssemblerARM32::emitVFPds
   1088 void Assembler::EmitVFPds(Condition cond, int32_t opcode,
   1089                           DRegister dd, SRegister sm) {
   1090   ASSERT(TargetCPUFeatures::vfp_supported());
   1091   ASSERT(dd != kNoDRegister);
   1092   ASSERT(sm != kNoSRegister);
   1093   ASSERT(cond != kNoCondition);
   1094   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
   1095                      B27 | B26 | B25 | B11 | B9 | opcode |
   1096                      ((static_cast<int32_t>(dd) >> 4)*B22) |
   1097                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
   1098                      ((static_cast<int32_t>(sm) & 1)*B5) |
   1099                      (static_cast<int32_t>(sm) >> 1);
   1100   Emit(encoding);
   1101 }
   1102 
   1103 // Moved to ARM32::AssemblerARM32::vcvtsd().
   1104 void Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
   1105   EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
   1106 }
   1107 
   1108 // Moved to ARM32::AssemblerARM32::vcvtds().
   1109 void Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
   1110   EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
   1111 }
   1112 
   1113 // Moved to ARM32::AssemblerARM32::vcvtis()
   1114 void Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
   1115   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
   1116 }
   1117 #endif
   1118 
   1119 void Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
   1120   EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
   1121 }
   1122 
   1123 #if 0
   1124 // Moved to ARM32::AssemblerARM32::vcvtsi()
   1125 void Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
   1126   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
   1127 }
   1128 
   1129 // Moved to ARM32::AssemblerARM32::vcvtdi()
   1130 void Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
   1131   EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
   1132 }
   1133 
   1134 // Moved to ARM32::AssemblerARM32::vcvtus().
   1135 void Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
   1136   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
   1137 }
   1138 
   1139 // Moved to ARM32::AssemblerARM32::vcvtud().
   1140 void Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
   1141   EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
   1142 }
   1143 
   1144 // Moved to ARM32::AssemblerARM32::vcvtsu()
   1145 void Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
   1146   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
   1147 }
   1148 
   1149 // Moved to ARM32::AssemblerARM32::vcvtdu()
   1150 void Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
   1151   EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
   1152 }
   1153 
   1154 // Moved to ARM23::AssemblerARM32::vcmps().
   1155 void Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
   1156   EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
   1157 }
   1158 
   1159 // Moved to ARM23::AssemblerARM32::vcmpd().
   1160 void Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
   1161   EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
   1162 }
   1163 
   1164 // Moved to ARM23::AssemblerARM32::vcmpsz().
   1165 void Assembler::vcmpsz(SRegister sd, Condition cond) {
   1166   EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
   1167 }
   1168 
   1169 // Moved to ARM23::AssemblerARM32::vcmpdz().
   1170 void Assembler::vcmpdz(DRegister dd, Condition cond) {
   1171   EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
   1172 }
   1173 
   1174 // APSR_nzcv version moved to ARM32::AssemblerARM32::vmrsAPSR_nzcv()
   1175 void Assembler::vmrs(Register rd, Condition cond) {
   1176   ASSERT(TargetCPUFeatures::vfp_supported());
   1177   ASSERT(cond != kNoCondition);
   1178   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
   1179                      B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
   1180                      (static_cast<int32_t>(rd)*B12) |
   1181                      B11 | B9 | B4;
   1182   Emit(encoding);
   1183 }
   1184 #endif
   1185 
   1186 void Assembler::vmstat(Condition cond) {
   1187   vmrs(APSR, cond);
   1188 }
   1189 
   1190 
   1191 static inline int ShiftOfOperandSize(OperandSize size) {
   1192   switch (size) {
   1193     case kByte:
   1194     case kUnsignedByte:
   1195       return 0;
   1196     case kHalfword:
   1197     case kUnsignedHalfword:
   1198       return 1;
   1199     case kWord:
   1200     case kUnsignedWord:
   1201       return 2;
   1202     case kWordPair:
   1203       return 3;
   1204     case kSWord:
   1205     case kDWord:
   1206       return 0;
   1207     default:
   1208       UNREACHABLE();
   1209       break;
   1210   }
   1211 
   1212   UNREACHABLE();
   1213   return -1;
   1214 }
   1215 
   1216 #if 0
   1217 // Moved to ARM32::AssemblerARM32::emitSIMDqqq()
   1218 void Assembler::EmitSIMDqqq(int32_t opcode, OperandSize size,
   1219                             QRegister qd, QRegister qn, QRegister qm) {
   1220   ASSERT(TargetCPUFeatures::neon_supported());
   1221   int sz = ShiftOfOperandSize(size);
   1222   int32_t encoding =
   1223       (static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
   1224       B25 | B6 |
   1225       opcode | ((sz & 0x3) * B20) |
   1226       ((static_cast<int32_t>(qd * 2) >> 4)*B22) |
   1227       ((static_cast<int32_t>(qn * 2) & 0xf)*B16) |
   1228       ((static_cast<int32_t>(qd * 2) & 0xf)*B12) |
   1229       ((static_cast<int32_t>(qn * 2) >> 4)*B7) |
   1230       ((static_cast<int32_t>(qm * 2) >> 4)*B5) |
   1231       (static_cast<int32_t>(qm * 2) & 0xf);
   1232   Emit(encoding);
   1233 }
   1234 #endif
   1235 
   1236 void Assembler::EmitSIMDddd(int32_t opcode, OperandSize size,
   1237                             DRegister dd, DRegister dn, DRegister dm) {
   1238   ASSERT(TargetCPUFeatures::neon_supported());
   1239   int sz = ShiftOfOperandSize(size);
   1240   int32_t encoding =
   1241       (static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
   1242       B25 |
   1243       opcode | ((sz & 0x3) * B20) |
   1244       ((static_cast<int32_t>(dd) >> 4)*B22) |
   1245       ((static_cast<int32_t>(dn) & 0xf)*B16) |
   1246       ((static_cast<int32_t>(dd) & 0xf)*B12) |
   1247       ((static_cast<int32_t>(dn) >> 4)*B7) |
   1248       ((static_cast<int32_t>(dm) >> 4)*B5) |
   1249       (static_cast<int32_t>(dm) & 0xf);
   1250   Emit(encoding);
   1251 }
   1252 
   1253 
   1254 void Assembler::vmovq(QRegister qd, QRegister qm) {
   1255   EmitSIMDqqq(B21 | B8 | B4, kByte, qd, qm, qm);
   1256 }
   1257 
   1258 #if 0
   1259 // Moved to ARM32::AssemblerARM32::vaddqi().
   1260 void Assembler::vaddqi(OperandSize sz,
   1261                        QRegister qd, QRegister qn, QRegister qm) {
   1262   EmitSIMDqqq(B11, sz, qd, qn, qm);
   1263 }
   1264 
   1265 // Moved to ARM32::AssemblerARM32::vaddqf().
   1266 void Assembler::vaddqs(QRegister qd, QRegister qn, QRegister qm) {
   1267   EmitSIMDqqq(B11 | B10 | B8, kSWord, qd, qn, qm);
   1268 }
   1269 #endif
   1270 
   1271 void Assembler::vsubqi(OperandSize sz,
   1272                        QRegister qd, QRegister qn, QRegister qm) {
   1273   EmitSIMDqqq(B24 | B11, sz, qd, qn, qm);
   1274 }
   1275 
   1276 
   1277 void Assembler::vsubqs(QRegister qd, QRegister qn, QRegister qm) {
   1278   EmitSIMDqqq(B21 | B11 | B10 | B8, kSWord, qd, qn, qm);
   1279 }
   1280 
   1281 #if 0
   1282 // Moved to ARM32::AssemblerARM32::vmulqi().
   1283 void Assembler::vmulqi(OperandSize sz,
   1284                        QRegister qd, QRegister qn, QRegister qm) {
   1285   EmitSIMDqqq(B11 | B8 | B4, sz, qd, qn, qm);
   1286 }
   1287 
   1288 // Moved to ARM32::AssemblerARM32::vmulqf().
   1289 void Assembler::vmulqs(QRegister qd, QRegister qn, QRegister qm) {
   1290   EmitSIMDqqq(B24 | B11 | B10 | B8 | B4, kSWord, qd, qn, qm);
   1291 }
   1292 
   1293 // Moved to ARM32::AssemblerARM32::vshlqi().
   1294 void Assembler::vshlqi(OperandSize sz,
   1295                        QRegister qd, QRegister qm, QRegister qn) {
   1296   EmitSIMDqqq(B25 | B10, sz, qd, qn, qm);
   1297 }
   1298 
   1299 
   1300 // Moved to ARM32::AssemblerARM32::vshlqu().
   1301 void Assembler::vshlqu(OperandSize sz,
   1302                        QRegister qd, QRegister qm, QRegister qn) {
   1303   EmitSIMDqqq(B25 | B24 | B10, sz, qd, qn, qm);
   1304 }
   1305 
   1306 // Moved to ARM32::AssemblerARM32::veorq()
   1307 void Assembler::veorq(QRegister qd, QRegister qn, QRegister qm) {
   1308   EmitSIMDqqq(B24 | B8 | B4, kByte, qd, qn, qm);
   1309 }
   1310 
   1311 // Moved to ARM32::AssemblerARM32::vorrq()
   1312 void Assembler::vorrq(QRegister qd, QRegister qn, QRegister qm) {
   1313   EmitSIMDqqq(B21 | B8 | B4, kByte, qd, qn, qm);
   1314 }
   1315 #endif
   1316 
   1317 void Assembler::vornq(QRegister qd, QRegister qn, QRegister qm) {
   1318   EmitSIMDqqq(B21 | B20 | B8 | B4, kByte, qd, qn, qm);
   1319 }
   1320 
   1321 #if 0
   1322 // Moved to ARM32::AssemblerARM32::vandq()
   1323 void Assembler::vandq(QRegister qd, QRegister qn, QRegister qm) {
   1324   EmitSIMDqqq(B8 | B4, kByte, qd, qn, qm);
   1325 }
   1326 
   1327 void Assembler::vmvnq(QRegister qd, QRegister qm) {
   1328   EmitSIMDqqq(B25 | B24 | B23 | B10 | B8 | B7, kWordPair, qd, Q0, qm);
   1329 }
   1330 #endif
   1331 
   1332 
   1333 void Assembler::vminqs(QRegister qd, QRegister qn, QRegister qm) {
   1334   EmitSIMDqqq(B21 | B11 | B10 | B9 | B8, kSWord, qd, qn, qm);
   1335 }
   1336 
   1337 
   1338 void Assembler::vmaxqs(QRegister qd, QRegister qn, QRegister qm) {
   1339   EmitSIMDqqq(B11 | B10 | B9 | B8, kSWord, qd, qn, qm);
   1340 }
   1341 
   1342 #if 0
   1343 // Moved to Arm32::AssemblerARM32::vabsq().
   1344 void Assembler::vabsqs(QRegister qd, QRegister qm) {
   1345   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B16 | B10 | B9 | B8, kSWord,
   1346               qd, Q0, qm);
   1347 }
   1348 
   1349 // Moved to Arm32::AssemblerARM32::vnegqs().
   1350 void Assembler::vnegqs(QRegister qd, QRegister qm) {
   1351   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B16 | B10 | B9 | B8 | B7, kSWord,
   1352               qd, Q0, qm);
   1353 }
   1354 #endif
   1355 
   1356 
   1357 void Assembler::vrecpeqs(QRegister qd, QRegister qm) {
   1358   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B8, kSWord,
   1359               qd, Q0, qm);
   1360 }
   1361 
   1362 
   1363 void Assembler::vrecpsqs(QRegister qd, QRegister qn, QRegister qm) {
   1364   EmitSIMDqqq(B11 | B10 | B9 | B8 | B4, kSWord, qd, qn, qm);
   1365 }
   1366 
   1367 
   1368 void Assembler::vrsqrteqs(QRegister qd, QRegister qm) {
   1369   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B8 | B7,
   1370               kSWord, qd, Q0, qm);
   1371 }
   1372 
   1373 
   1374 void Assembler::vrsqrtsqs(QRegister qd, QRegister qn, QRegister qm) {
   1375   EmitSIMDqqq(B21 | B11 | B10 | B9 | B8 | B4, kSWord, qd, qn, qm);
   1376 }
   1377 
   1378 
   1379 void Assembler::vdup(OperandSize sz, QRegister qd, DRegister dm, int idx) {
   1380   ASSERT((sz != kDWord) && (sz != kSWord) && (sz != kWordPair));
   1381   int code = 0;
   1382 
   1383   switch (sz) {
   1384     case kByte:
   1385     case kUnsignedByte: {
   1386       ASSERT((idx >= 0) && (idx < 8));
   1387       code = 1 | (idx << 1);
   1388       break;
   1389     }
   1390     case kHalfword:
   1391     case kUnsignedHalfword: {
   1392       ASSERT((idx >= 0) && (idx < 4));
   1393       code = 2 | (idx << 2);
   1394       break;
   1395     }
   1396     case kWord:
   1397     case kUnsignedWord: {
   1398       ASSERT((idx >= 0) && (idx < 2));
   1399       code = 4 | (idx << 3);
   1400       break;
   1401     }
   1402     default: {
   1403       break;
   1404     }
   1405   }
   1406 
   1407   EmitSIMDddd(B24 | B23 | B11 | B10 | B6, kWordPair,
   1408               static_cast<DRegister>(qd * 2),
   1409               static_cast<DRegister>(code & 0xf),
   1410               dm);
   1411 }
   1412 
   1413 
   1414 void Assembler::vtbl(DRegister dd, DRegister dn, int len, DRegister dm) {
   1415   ASSERT((len >= 1) && (len <= 4));
   1416   EmitSIMDddd(B24 | B23 | B11 | ((len - 1) * B8), kWordPair, dd, dn, dm);
   1417 }
   1418 
   1419 
   1420 void Assembler::vzipqw(QRegister qd, QRegister qm) {
   1421   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B8 | B7, kByte, qd, Q0, qm);
   1422 }
   1423 
   1424 
   1425 #if 0
   1426 // Moved to Arm32::AssemblerARM32::vceqqi().
   1427 void Assembler::vceqqi(OperandSize sz,
   1428                       QRegister qd, QRegister qn, QRegister qm) {
   1429   EmitSIMDqqq(B24 | B11 | B4, sz, qd, qn, qm);
   1430 }
   1431 
   1432 // Moved to Arm32::AssemblerARM32::vceqqi().
   1433 void Assembler::vceqqs(QRegister qd, QRegister qn, QRegister qm) {
   1434   EmitSIMDqqq(B11 | B10 | B9, kSWord, qd, qn, qm);
   1435 }
   1436 
   1437 // Moved to Arm32::AssemblerARM32::vcgeqi().
   1438 void Assembler::vcgeqi(OperandSize sz,
   1439                       QRegister qd, QRegister qn, QRegister qm) {
   1440   EmitSIMDqqq(B9 | B8 | B4, sz, qd, qn, qm);
   1441 }
   1442 
   1443 // Moved to Arm32::AssemblerARM32::vcugeqi().
   1444 void Assembler::vcugeqi(OperandSize sz,
   1445                       QRegister qd, QRegister qn, QRegister qm) {
   1446   EmitSIMDqqq(B24 | B9 | B8 | B4, sz, qd, qn, qm);
   1447 }
   1448 
   1449 // Moved to Arm32::AssemblerARM32::vcgeqs().
   1450 void Assembler::vcgeqs(QRegister qd, QRegister qn, QRegister qm) {
   1451   EmitSIMDqqq(B24 | B11 | B10 | B9, kSWord, qd, qn, qm);
   1452 }
   1453 
   1454 // Moved to Arm32::AssemblerARM32::vcgtqi().
   1455 void Assembler::vcgtqi(OperandSize sz,
   1456                       QRegister qd, QRegister qn, QRegister qm) {
   1457   EmitSIMDqqq(B9 | B8, sz, qd, qn, qm);
   1458 }
   1459 
   1460 // Moved to Arm32::AssemblerARM32::vcugtqi().
   1461 void Assembler::vcugtqi(OperandSize sz,
   1462                       QRegister qd, QRegister qn, QRegister qm) {
   1463   EmitSIMDqqq(B24 | B9 | B8, sz, qd, qn, qm);
   1464 }
   1465 
   1466 // Moved to Arm32::AssemblerARM32::vcgtqs().
   1467 void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) {
   1468   EmitSIMDqqq(B24 | B21 | B11 | B10 | B9, kSWord, qd, qn, qm);
   1469 }
   1470 
   1471 // Moved to ARM32::AssemblerARM32::bkpt()
   1472 void Assembler::bkpt(uint16_t imm16) {
   1473   Emit(BkptEncoding(imm16));
   1474 }
   1475 #endif
   1476 
   1477 
   1478 void Assembler::b(Label* label, Condition cond) {
   1479   EmitBranch(cond, label, false);
   1480 }
   1481 
   1482 
   1483 #if 0
   1484 // Moved to ARM32::AssemblerARM32::bl()
   1485 void Assembler::bl(Label* label, Condition cond) {
   1486   EmitBranch(cond, label, true);
   1487 }
   1488 
   1489 // Moved to ARM32::AssemblerARM32::bx()
   1490 void Assembler::bx(Register rm, Condition cond) {
   1491   ASSERT(rm != kNoRegister);
   1492   ASSERT(cond != kNoCondition);
   1493   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
   1494                      B24 | B21 | (0xfff << 8) | B4 |
   1495                      (static_cast<int32_t>(rm) << kRmShift);
   1496   Emit(encoding);
   1497 }
   1498 
   1499 // Moved to ARM32::AssemblerARM32::blx()
   1500 void Assembler::blx(Register rm, Condition cond) {
   1501   ASSERT(rm != kNoRegister);
   1502   ASSERT(cond != kNoCondition);
   1503   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
   1504                      B24 | B21 | (0xfff << 8) | B5 | B4 |
   1505                      (static_cast<int32_t>(rm) << kRmShift);
   1506   Emit(encoding);
   1507 }
   1508 #endif
   1509 
   1510 
   1511 void Assembler::MarkExceptionHandler(Label* label) {
   1512   EmitType01(AL, 1, TST, 1, PC, R0, Operand(0));
   1513   Label l;
   1514   b(&l);
   1515   EmitBranch(AL, label, false);
   1516   Bind(&l);
   1517 }
   1518 
   1519 
   1520 void Assembler::Drop(intptr_t stack_elements) {
   1521   ASSERT(stack_elements >= 0);
   1522   if (stack_elements > 0) {
   1523     AddImmediate(SP, SP, stack_elements * kWordSize);
   1524   }
   1525 }
   1526 
   1527 
   1528 intptr_t Assembler::FindImmediate(int32_t imm) {
   1529   return object_pool_wrapper_.FindImmediate(imm);
   1530 }
   1531 
   1532 
   1533 // Uses a code sequence that can easily be decoded.
   1534 void Assembler::LoadWordFromPoolOffset(Register rd,
   1535                                        int32_t offset,
   1536                                        Register pp,
   1537                                        Condition cond) {
   1538   ASSERT((pp != PP) || constant_pool_allowed());
   1539   ASSERT(rd != pp);
   1540   int32_t offset_mask = 0;
   1541   if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) {
   1542     ldr(rd, Address(pp, offset), cond);
   1543   } else {
   1544     int32_t offset_hi = offset & ~offset_mask;  // signed
   1545     uint32_t offset_lo = offset & offset_mask;  // unsigned
   1546     // Inline a simplified version of AddImmediate(rd, pp, offset_hi).
   1547     Operand o;
   1548     if (Operand::CanHold(offset_hi, &o)) {
   1549       add(rd, pp, o, cond);
   1550     } else {
   1551       LoadImmediate(rd, offset_hi, cond);
   1552       add(rd, pp, Operand(rd), cond);
   1553     }
   1554     ldr(rd, Address(rd, offset_lo), cond);
   1555   }
   1556 }
   1557 
   1558 void Assembler::CheckCodePointer() {
   1559 #ifdef DEBUG
   1560   Label cid_ok, instructions_ok;
   1561   Push(R0);
   1562   Push(IP);
   1563   CompareClassId(CODE_REG, kCodeCid, R0);
   1564   b(&cid_ok, EQ);
   1565   bkpt(0);
   1566   Bind(&cid_ok);
   1567 
   1568   const intptr_t offset = CodeSize() + Instr::kPCReadOffset +
   1569       Instructions::HeaderSize() - kHeapObjectTag;
   1570   mov(R0, Operand(PC));
   1571   AddImmediate(R0, R0, -offset);
   1572   ldr(IP, FieldAddress(CODE_REG, Code::saved_instructions_offset()));
   1573   cmp(R0, Operand(IP));
   1574   b(&instructions_ok, EQ);
   1575   bkpt(1);
   1576   Bind(&instructions_ok);
   1577   Pop(IP);
   1578   Pop(R0);
   1579 #endif
   1580 }
   1581 
   1582 
   1583 void Assembler::RestoreCodePointer() {
   1584   ldr(CODE_REG, Address(FP, kPcMarkerSlotFromFp * kWordSize));
   1585   CheckCodePointer();
   1586 }
   1587 
   1588 
   1589 void Assembler::LoadPoolPointer(Register reg) {
   1590   // Load new pool pointer.
   1591   CheckCodePointer();
   1592   ldr(reg, FieldAddress(CODE_REG, Code::object_pool_offset()));
   1593   set_constant_pool_allowed(reg == PP);
   1594 }
   1595 
   1596 
   1597 void Assembler::LoadIsolate(Register rd) {
   1598   ldr(rd, Address(THR, Thread::isolate_offset()));
   1599 }
   1600 
   1601 
   1602 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   1603   ASSERT(!Thread::CanLoadFromThread(object));
   1604   if (!constant_pool_allowed()) {
   1605     return false;
   1606   }
   1607 
   1608   ASSERT(object.IsNotTemporaryScopedHandle());
   1609   ASSERT(object.IsOld());
   1610   return true;
   1611 }
   1612 
   1613 
   1614 void Assembler::LoadObjectHelper(Register rd,
   1615                                  const Object& object,
   1616                                  Condition cond,
   1617                                  bool is_unique,
   1618                                  Register pp) {
   1619   // Load common VM constants from the thread. This works also in places where
   1620   // no constant pool is set up (e.g. intrinsic code).
   1621   if (Thread::CanLoadFromThread(object)) {
   1622     // Load common VM constants from the thread. This works also in places where
   1623     // no constant pool is set up (e.g. intrinsic code).
   1624     ldr(rd, Address(THR, Thread::OffsetFromThread(object)), cond);
   1625   } else if (object.IsSmi()) {
   1626     // Relocation doesn't apply to Smis.
   1627     LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
   1628   } else if (CanLoadFromObjectPool(object)) {
   1629     // Make sure that class CallPattern is able to decode this load from the
   1630     // object pool.
   1631     const int32_t offset = ObjectPool::element_offset(
   1632        is_unique ? object_pool_wrapper_.AddObject(object)
   1633                  : object_pool_wrapper_.FindObject(object));
   1634     LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, pp, cond);
   1635   } else {
   1636     ASSERT(FLAG_allow_absolute_addresses);
   1637     ASSERT(object.IsOld());
   1638     // Make sure that class CallPattern is able to decode this load immediate.
   1639     const int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
   1640     LoadImmediate(rd, object_raw, cond);
   1641   }
   1642 }
   1643 
   1644 
   1645 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
   1646   LoadObjectHelper(rd, object, cond, /* is_unique = */ false, PP);
   1647 }
   1648 
   1649 
   1650 void Assembler::LoadUniqueObject(Register rd,
   1651                                  const Object& object,
   1652                                  Condition cond) {
   1653   LoadObjectHelper(rd, object, cond, /* is_unique = */ true, PP);
   1654 }
   1655 
   1656 
   1657 void Assembler::LoadFunctionFromCalleePool(Register dst,
   1658                                            const Function& function,
   1659                                            Register new_pp) {
   1660   const int32_t offset =
   1661       ObjectPool::element_offset(object_pool_wrapper_.FindObject(function));
   1662   LoadWordFromPoolOffset(dst, offset - kHeapObjectTag, new_pp, AL);
   1663 }
   1664 
   1665 
   1666 void Assembler::LoadNativeEntry(Register rd,
   1667                                 const ExternalLabel* label,
   1668                                 Patchability patchable,
   1669                                 Condition cond) {
   1670   const int32_t offset = ObjectPool::element_offset(
   1671       object_pool_wrapper_.FindNativeEntry(label, patchable));
   1672   LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond);
   1673 }
   1674 
   1675 
   1676 void Assembler::PushObject(const Object& object) {
   1677   LoadObject(IP, object);
   1678   Push(IP);
   1679 }
   1680 
   1681 
   1682 void Assembler::CompareObject(Register rn, const Object& object) {
   1683   ASSERT(rn != IP);
   1684   if (object.IsSmi()) {
   1685     CompareImmediate(rn, reinterpret_cast<int32_t>(object.raw()));
   1686   } else {
   1687     LoadObject(IP, object);
   1688     cmp(rn, Operand(IP));
   1689   }
   1690 }
   1691 
   1692 
   1693 // Preserves object and value registers.
   1694 void Assembler::StoreIntoObjectFilterNoSmi(Register object,
   1695                                            Register value,
   1696                                            Label* no_update) {
   1697   COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) &&
   1698                  (kOldObjectAlignmentOffset == 0));
   1699 
   1700   // Write-barrier triggers if the value is in the new space (has bit set) and
   1701   // the object is in the old space (has bit cleared).
   1702   // To check that, we compute value & ~object and skip the write barrier
   1703   // if the bit is not set. We can't destroy the object.
   1704   bic(IP, value, Operand(object));
   1705   tst(IP, Operand(kNewObjectAlignmentOffset));
   1706   b(no_update, EQ);
   1707 }
   1708 
   1709 
   1710 // Preserves object and value registers.
   1711 void Assembler::StoreIntoObjectFilter(Register object,
   1712                                       Register value,
   1713                                       Label* no_update) {
   1714   // For the value we are only interested in the new/old bit and the tag bit.
   1715   // And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
   1716   and_(IP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1));
   1717   // And the result with the negated space bit of the object.
   1718   bic(IP, IP, Operand(object));
   1719   tst(IP, Operand(kNewObjectAlignmentOffset));
   1720   b(no_update, EQ);
   1721 }
   1722 
   1723 
   1724 Operand Assembler::GetVerifiedMemoryShadow() {
   1725   Operand offset;
   1726   if (!Operand::CanHold(VerifiedMemory::offset(), &offset)) {
   1727     FATAL1("Offset 0x%" Px " not representable", VerifiedMemory::offset());
   1728   }
   1729   return offset;
   1730 }
   1731 
   1732 
   1733 void Assembler::WriteShadowedField(Register base,
   1734                                    intptr_t offset,
   1735                                    Register value,
   1736                                    Condition cond) {
   1737   if (VerifiedMemory::enabled()) {
   1738     ASSERT(base != value);
   1739     Operand shadow(GetVerifiedMemoryShadow());
   1740     add(base, base, shadow, cond);
   1741     str(value, Address(base, offset), cond);
   1742     sub(base, base, shadow, cond);
   1743   }
   1744   str(value, Address(base, offset), cond);
   1745 }
   1746 
   1747 
   1748 void Assembler::WriteShadowedFieldPair(Register base,
   1749                                        intptr_t offset,
   1750                                        Register value_even,
   1751                                        Register value_odd,
   1752                                        Condition cond) {
   1753   ASSERT(value_odd == value_even + 1);
   1754   if (VerifiedMemory::enabled()) {
   1755     ASSERT(base != value_even);
   1756     ASSERT(base != value_odd);
   1757     Operand shadow(GetVerifiedMemoryShadow());
   1758     add(base, base, shadow, cond);
   1759     strd(value_even, base, offset, cond);
   1760     sub(base, base, shadow, cond);
   1761   }
   1762   strd(value_even, base, offset, cond);
   1763 }
   1764 
   1765 
   1766 Register UseRegister(Register reg, RegList* used) {
   1767   ASSERT(reg != SP);
   1768   ASSERT(reg != PC);
   1769   ASSERT((*used & (1 << reg)) == 0);
   1770   *used |= (1 << reg);
   1771   return reg;
   1772 }
   1773 
   1774 
   1775 Register AllocateRegister(RegList* used) {
   1776   const RegList free = ~*used;
   1777   return (free == 0) ?
   1778       kNoRegister :
   1779       UseRegister(static_cast<Register>(Utils::CountTrailingZeros(free)), used);
   1780 }
   1781 
   1782 
   1783 void Assembler::VerifiedWrite(const Address& address,
   1784                               Register new_value,
   1785                               FieldContent old_content) {
   1786 #if defined(DEBUG)
   1787   ASSERT(address.mode() == Address::Offset ||
   1788          address.mode() == Address::NegOffset);
   1789   // Allocate temporary registers (and check for register collisions).
   1790   RegList used = 0;
   1791   UseRegister(new_value, &used);
   1792   Register base = UseRegister(address.rn(), &used);
   1793   if (address.rm() != kNoRegister) {
   1794     UseRegister(address.rm(), &used);
   1795   }
   1796   Register old_value = AllocateRegister(&used);
   1797   Register temp = AllocateRegister(&used);
   1798   PushList(used);
   1799   ldr(old_value, address);
   1800   // First check that 'old_value' contains 'old_content'.
   1801   // Smi test.
   1802   tst(old_value, Operand(kHeapObjectTag));
   1803   Label ok;
   1804   switch (old_content) {
   1805     case kOnlySmi:
   1806       b(&ok, EQ);  // Smi is OK.
   1807       Stop("Expected smi.");
   1808       break;
   1809     case kHeapObjectOrSmi:
   1810       b(&ok, EQ);  // Smi is OK.
   1811       // Non-smi case: Verify object pointer is word-aligned when untagged.
   1812       COMPILE_ASSERT(kHeapObjectTag == 1);
   1813       tst(old_value, Operand((kWordSize - 1) - kHeapObjectTag));
   1814       b(&ok, EQ);
   1815       Stop("Expected heap object or Smi");
   1816       break;
   1817     case kEmptyOrSmiOrNull:
   1818       b(&ok, EQ);  // Smi is OK.
   1819       // Non-smi case: Check for the special zap word or null.
   1820       // Note: Cannot use CompareImmediate, since IP may be in use.
   1821       LoadImmediate(temp, Heap::kZap32Bits);
   1822       cmp(old_value, Operand(temp));
   1823       b(&ok, EQ);
   1824       LoadObject(temp, Object::null_object());
   1825       cmp(old_value, Operand(temp));
   1826       b(&ok, EQ);
   1827       Stop("Expected zapped, Smi or null");
   1828       break;
   1829     default:
   1830       UNREACHABLE();
   1831   }
   1832   Bind(&ok);
   1833   if (VerifiedMemory::enabled()) {
   1834     Operand shadow_offset(GetVerifiedMemoryShadow());
   1835     // Adjust the address to shadow.
   1836     add(base, base, shadow_offset);
   1837     ldr(temp, address);
   1838     cmp(old_value, Operand(temp));
   1839     Label match;
   1840     b(&match, EQ);
   1841     Stop("Write barrier verification failed");
   1842     Bind(&match);
   1843     // Write new value in shadow.
   1844     str(new_value, address);
   1845     // Restore original address.
   1846     sub(base, base, shadow_offset);
   1847   }
   1848   str(new_value, address);
   1849   PopList(used);
   1850 #else
   1851   str(new_value, address);
   1852 #endif  // DEBUG
   1853 }
   1854 
   1855 
   1856 void Assembler::StoreIntoObject(Register object,
   1857                                 const Address& dest,
   1858                                 Register value,
   1859                                 bool can_value_be_smi) {
   1860   ASSERT(object != value);
   1861   VerifiedWrite(dest, value, kHeapObjectOrSmi);
   1862   Label done;
   1863   if (can_value_be_smi) {
   1864     StoreIntoObjectFilter(object, value, &done);
   1865   } else {
   1866     StoreIntoObjectFilterNoSmi(object, value, &done);
   1867   }
   1868   // A store buffer update is required.
   1869   RegList regs = (1 << CODE_REG) | (1 << LR);
   1870   if (value != R0) {
   1871     regs |= (1 << R0);  // Preserve R0.
   1872   }
   1873   PushList(regs);
   1874   if (object != R0) {
   1875     mov(R0, Operand(object));
   1876   }
   1877   ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   1878   ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset()));
   1879   blx(LR);
   1880   PopList(regs);
   1881   Bind(&done);
   1882 }
   1883 
   1884 
   1885 void Assembler::StoreIntoObjectOffset(Register object,
   1886                                       int32_t offset,
   1887                                       Register value,
   1888                                       bool can_value_be_smi) {
   1889   int32_t ignored = 0;
   1890   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
   1891     StoreIntoObject(
   1892         object, FieldAddress(object, offset), value, can_value_be_smi);
   1893   } else {
   1894     AddImmediate(IP, object, offset - kHeapObjectTag);
   1895     StoreIntoObject(object, Address(IP), value, can_value_be_smi);
   1896   }
   1897 }
   1898 
   1899 
   1900 void Assembler::StoreIntoObjectNoBarrier(Register object,
   1901                                          const Address& dest,
   1902                                          Register value,
   1903                                          FieldContent old_content) {
   1904   VerifiedWrite(dest, value, old_content);
   1905 #if defined(DEBUG)
   1906   Label done;
   1907   StoreIntoObjectFilter(object, value, &done);
   1908   Stop("Store buffer update is required");
   1909   Bind(&done);
   1910 #endif  // defined(DEBUG)
   1911   // No store buffer update.
   1912 }
   1913 
   1914 
   1915 void Assembler::StoreIntoObjectNoBarrierOffset(Register object,
   1916                                                int32_t offset,
   1917                                                Register value,
   1918                                                FieldContent old_content) {
   1919   int32_t ignored = 0;
   1920   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
   1921     StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
   1922                              old_content);
   1923   } else {
   1924     AddImmediate(IP, object, offset - kHeapObjectTag);
   1925     StoreIntoObjectNoBarrier(object, Address(IP), value, old_content);
   1926   }
   1927 }
   1928 
   1929 
   1930 void Assembler::StoreIntoObjectNoBarrier(Register object,
   1931                                          const Address& dest,
   1932                                          const Object& value,
   1933                                          FieldContent old_content) {
   1934   ASSERT(value.IsSmi() || value.InVMHeap() ||
   1935          (value.IsOld() && value.IsNotTemporaryScopedHandle()));
   1936   // No store buffer update.
   1937   LoadObject(IP, value);
   1938   VerifiedWrite(dest, IP, old_content);
   1939 }
   1940 
   1941 
   1942 void Assembler::StoreIntoObjectNoBarrierOffset(Register object,
   1943                                                int32_t offset,
   1944                                                const Object& value,
   1945                                                FieldContent old_content) {
   1946   int32_t ignored = 0;
   1947   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
   1948     StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
   1949                              old_content);
   1950   } else {
   1951     AddImmediate(IP, object, offset - kHeapObjectTag);
   1952     StoreIntoObjectNoBarrier(object, Address(IP), value, old_content);
   1953   }
   1954 }
   1955 
   1956 
   1957 void Assembler::InitializeFieldsNoBarrier(Register object,
   1958                                           Register begin,
   1959                                           Register end,
   1960                                           Register value_even,
   1961                                           Register value_odd) {
   1962   ASSERT(value_odd == value_even + 1);
   1963   Label init_loop;
   1964   Bind(&init_loop);
   1965   AddImmediate(begin, 2 * kWordSize);
   1966   cmp(begin, Operand(end));
   1967   WriteShadowedFieldPair(begin, -2 * kWordSize, value_even, value_odd, LS);
   1968   b(&init_loop, CC);
   1969   WriteShadowedField(begin, -2 * kWordSize, value_even, HI);
   1970 #if defined(DEBUG)
   1971   Label done;
   1972   StoreIntoObjectFilter(object, value_even, &done);
   1973   StoreIntoObjectFilter(object, value_odd, &done);
   1974   Stop("Store buffer update is required");
   1975   Bind(&done);
   1976 #endif  // defined(DEBUG)
   1977   // No store buffer update.
   1978 }
   1979 
   1980 
   1981 void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
   1982                                                   Register base,
   1983                                                   intptr_t begin_offset,
   1984                                                   intptr_t end_offset,
   1985                                                   Register value_even,
   1986                                                   Register value_odd) {
   1987   ASSERT(value_odd == value_even + 1);
   1988   intptr_t current_offset = begin_offset;
   1989   while (current_offset + kWordSize < end_offset) {
   1990     WriteShadowedFieldPair(base, current_offset, value_even, value_odd);
   1991     current_offset += 2*kWordSize;
   1992   }
   1993   while (current_offset < end_offset) {
   1994     WriteShadowedField(base, current_offset, value_even);
   1995     current_offset += kWordSize;
   1996   }
   1997 #if defined(DEBUG)
   1998   Label done;
   1999   StoreIntoObjectFilter(object, value_even, &done);
   2000   StoreIntoObjectFilter(object, value_odd, &done);
   2001   Stop("Store buffer update is required");
   2002   Bind(&done);
   2003 #endif  // defined(DEBUG)
   2004   // No store buffer update.
   2005 }
   2006 
   2007 
   2008 void Assembler::StoreIntoSmiField(const Address& dest, Register value) {
   2009 #if defined(DEBUG)
   2010   Label done;
   2011   tst(value, Operand(kHeapObjectTag));
   2012   b(&done, EQ);
   2013   Stop("New value must be Smi.");
   2014   Bind(&done);
   2015 #endif  // defined(DEBUG)
   2016   VerifiedWrite(dest, value, kOnlySmi);
   2017 }
   2018 
   2019 
   2020 void Assembler::LoadClassId(Register result, Register object, Condition cond) {
   2021   ASSERT(RawObject::kClassIdTagPos == 16);
   2022   ASSERT(RawObject::kClassIdTagSize == 16);
   2023   const intptr_t class_id_offset = Object::tags_offset() +
   2024       RawObject::kClassIdTagPos / kBitsPerByte;
   2025   ldrh(result, FieldAddress(object, class_id_offset), cond);
   2026 }
   2027 
   2028 
   2029 void Assembler::LoadClassById(Register result, Register class_id) {
   2030   ASSERT(result != class_id);
   2031   LoadIsolate(result);
   2032   const intptr_t offset =
   2033       Isolate::class_table_offset() + ClassTable::table_offset();
   2034   LoadFromOffset(kWord, result, result, offset);
   2035   ldr(result, Address(result, class_id, LSL, 2));
   2036 }
   2037 
   2038 
   2039 void Assembler::LoadClass(Register result, Register object, Register scratch) {
   2040   ASSERT(scratch != result);
   2041   LoadClassId(scratch, object);
   2042   LoadClassById(result, scratch);
   2043 }
   2044 
   2045 
   2046 void Assembler::CompareClassId(Register object,
   2047                                intptr_t class_id,
   2048                                Register scratch) {
   2049   LoadClassId(scratch, object);
   2050   CompareImmediate(scratch, class_id);
   2051 }
   2052 
   2053 
   2054 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   2055   tst(object, Operand(kSmiTagMask));
   2056   LoadClassId(result, object, NE);
   2057   LoadImmediate(result, kSmiCid, EQ);
   2058 }
   2059 
   2060 
   2061 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
   2062   LoadClassIdMayBeSmi(result, object);
   2063   SmiTag(result);
   2064 }
   2065 
   2066 
   2067 void Assembler::ComputeRange(Register result,
   2068                              Register value,
   2069                              Register scratch,
   2070                              Label* not_mint) {
   2071   const Register hi = TMP;
   2072   const Register lo = scratch;
   2073 
   2074   Label done;
   2075   mov(result, Operand(value, LSR, kBitsPerWord - 1));
   2076   tst(value, Operand(kSmiTagMask));
   2077   b(&done, EQ);
   2078   CompareClassId(value, kMintCid, result);
   2079   b(not_mint, NE);
   2080   ldr(hi, FieldAddress(value, Mint::value_offset() + kWordSize));
   2081   ldr(lo, FieldAddress(value, Mint::value_offset()));
   2082   rsb(result, hi, Operand(ICData::kInt32RangeBit));
   2083   cmp(hi, Operand(lo, ASR, kBitsPerWord - 1));
   2084   b(&done, EQ);
   2085   LoadImmediate(result, ICData::kUint32RangeBit);  // Uint32
   2086   tst(hi, Operand(hi));
   2087   LoadImmediate(result, ICData::kInt64RangeBit, NE);  // Int64
   2088   Bind(&done);
   2089 }
   2090 
   2091 
   2092 void Assembler::UpdateRangeFeedback(Register value,
   2093                                     intptr_t index,
   2094                                     Register ic_data,
   2095                                     Register scratch1,
   2096                                     Register scratch2,
   2097                                     Label* miss) {
   2098   ASSERT(ICData::IsValidRangeFeedbackIndex(index));
   2099   ComputeRange(scratch1, value, scratch2, miss);
   2100   ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
   2101   orr(scratch2,
   2102       scratch2,
   2103       Operand(scratch1, LSL, ICData::RangeFeedbackShift(index)));
   2104   str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
   2105 }
   2106 
   2107 #if 0
   2108 // Moved to ::canEncodeBranchoffset() in IceAssemblerARM32.cpp.
   2109 static bool CanEncodeBranchOffset(int32_t offset) {
   2110   ASSERT(Utils::IsAligned(offset, 4));
   2111   // Note: This check doesn't take advantage of the fact that offset>>2
   2112   // is stored (allowing two more bits in address space).
   2113   return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
   2114 }
   2115 
   2116 // Moved to ARM32::AssemblerARM32::encodeBranchOffset()
   2117 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
   2118   // The offset is off by 8 due to the way the ARM CPUs read PC.
   2119   offset -= Instr::kPCReadOffset;
   2120 
   2121   if (!CanEncodeBranchOffset(offset)) {
   2122     ASSERT(!use_far_branches());
   2123     Thread::Current()->long_jump_base()->Jump(
   2124         1, Object::branch_offset_error());
   2125   }
   2126 
   2127   // Properly preserve only the bits supported in the instruction.
   2128   offset >>= 2;
   2129   offset &= kBranchOffsetMask;
   2130   return (inst & ~kBranchOffsetMask) | offset;
   2131 }
   2132 
   2133 // Moved to AssemberARM32::decodeBranchOffset()
   2134 int Assembler::DecodeBranchOffset(int32_t inst) {
   2135   // Sign-extend, left-shift by 2, then add 8.
   2136   return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
   2137 }
   2138 #endif
   2139 
   2140 static int32_t DecodeARMv7LoadImmediate(int32_t movt, int32_t movw) {
   2141   int32_t offset = 0;
   2142   offset |= (movt & 0xf0000) << 12;
   2143   offset |= (movt & 0xfff) << 16;
   2144   offset |= (movw & 0xf0000) >> 4;
   2145   offset |= movw & 0xfff;
   2146   return offset;
   2147 }
   2148 
   2149 
   2150 static int32_t DecodeARMv6LoadImmediate(int32_t mov, int32_t or1,
   2151                                         int32_t or2, int32_t or3) {
   2152   int32_t offset = 0;
   2153   offset |= (mov & 0xff) << 24;
   2154   offset |= (or1 & 0xff) << 16;
   2155   offset |= (or2 & 0xff) << 8;
   2156   offset |= (or3 & 0xff);
   2157   return offset;
   2158 }
   2159 
   2160 
   2161 class PatchFarBranch : public AssemblerFixup {
   2162  public:
   2163   PatchFarBranch() {}
   2164 
   2165   void Process(const MemoryRegion& region, intptr_t position) {
   2166     const ARMVersion version = TargetCPUFeatures::arm_version();
   2167     if ((version == ARMv5TE) || (version == ARMv6)) {
   2168       ProcessARMv6(region, position);
   2169     } else {
   2170       ASSERT(version == ARMv7);
   2171       ProcessARMv7(region, position);
   2172     }
   2173   }
   2174 
   2175  private:
   2176   void ProcessARMv6(const MemoryRegion& region, intptr_t position) {
   2177     const int32_t mov = region.Load<int32_t>(position);
   2178     const int32_t or1 = region.Load<int32_t>(position + 1*Instr::kInstrSize);
   2179     const int32_t or2 = region.Load<int32_t>(position + 2*Instr::kInstrSize);
   2180     const int32_t or3 = region.Load<int32_t>(position + 3*Instr::kInstrSize);
   2181     const int32_t bx = region.Load<int32_t>(position + 4*Instr::kInstrSize);
   2182 
   2183     if (((mov & 0xffffff00) == 0xe3a0c400) &&  // mov IP, (byte3 rot 4)
   2184         ((or1 & 0xffffff00) == 0xe38cc800) &&  // orr IP, IP, (byte2 rot 8)
   2185         ((or2 & 0xffffff00) == 0xe38ccc00) &&  // orr IP, IP, (byte1 rot 12)
   2186         ((or3 & 0xffffff00) == 0xe38cc000)) {  // orr IP, IP, byte0
   2187       const int32_t offset = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
   2188       const int32_t dest = region.start() + offset;
   2189       const int32_t dest0 = (dest & 0x000000ff);
   2190       const int32_t dest1 = (dest & 0x0000ff00) >> 8;
   2191       const int32_t dest2 = (dest & 0x00ff0000) >> 16;
   2192       const int32_t dest3 = (dest & 0xff000000) >> 24;
   2193       const int32_t patched_mov = 0xe3a0c400 | dest3;
   2194       const int32_t patched_or1 = 0xe38cc800 | dest2;
   2195       const int32_t patched_or2 = 0xe38ccc00 | dest1;
   2196       const int32_t patched_or3 = 0xe38cc000 | dest0;
   2197 
   2198       region.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov);
   2199       region.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1);
   2200       region.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2);
   2201       region.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3);
   2202       return;
   2203     }
   2204 
   2205     // If the offset loading instructions aren't there, we must have replaced
   2206     // the far branch with a near one, and so these instructions
   2207     // should be NOPs.
   2208     ASSERT((or1 == Instr::kNopInstruction) &&
   2209            (or2 == Instr::kNopInstruction) &&
   2210            (or3 == Instr::kNopInstruction) &&
   2211            (bx == Instr::kNopInstruction));
   2212   }
   2213 
   2214 
   2215   void ProcessARMv7(const MemoryRegion& region, intptr_t position) {
   2216     const int32_t movw = region.Load<int32_t>(position);
   2217     const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize);
   2218     const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize);
   2219 
   2220     if (((movt & 0xfff0f000) == 0xe340c000) &&  // movt IP, high
   2221         ((movw & 0xfff0f000) == 0xe300c000)) {   // movw IP, low
   2222       const int32_t offset = DecodeARMv7LoadImmediate(movt, movw);
   2223       const int32_t dest = region.start() + offset;
   2224       const uint16_t dest_high = Utils::High16Bits(dest);
   2225       const uint16_t dest_low = Utils::Low16Bits(dest);
   2226       const int32_t patched_movt =
   2227           0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
   2228       const int32_t patched_movw =
   2229           0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
   2230 
   2231       region.Store<int32_t>(position, patched_movw);
   2232       region.Store<int32_t>(position + Instr::kInstrSize, patched_movt);
   2233       return;
   2234     }
   2235 
   2236     // If the offset loading instructions aren't there, we must have replaced
   2237     // the far branch with a near one, and so these instructions
   2238     // should be NOPs.
   2239     ASSERT((movt == Instr::kNopInstruction) &&
   2240            (bx == Instr::kNopInstruction));
   2241   }
   2242 
   2243   virtual bool IsPointerOffset() const { return false; }
   2244 };
   2245 
   2246 
   2247 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) {
   2248   buffer_.EmitFixup(new PatchFarBranch());
   2249   LoadPatchableImmediate(IP, offset);
   2250   if (link) {
   2251     blx(IP, cond);
   2252   } else {
   2253     bx(IP, cond);
   2254   }
   2255 }
   2256 
   2257 
   2258 void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
   2259   if (label->IsBound()) {
   2260     const int32_t dest = label->Position() - buffer_.Size();
   2261     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
   2262       EmitFarBranch(cond, label->Position(), link);
   2263     } else {
   2264       EmitType5(cond, dest, link);
   2265     }
   2266   } else {
   2267     const intptr_t position = buffer_.Size();
   2268     if (use_far_branches()) {
   2269       const int32_t dest = label->position_;
   2270       EmitFarBranch(cond, dest, link);
   2271     } else {
   2272       // Use the offset field of the branch instruction for linking the sites.
   2273       EmitType5(cond, label->position_, link);
   2274     }
   2275     label->LinkTo(position);
   2276   }
   2277 }
   2278 
   2279 
   2280 void Assembler::BindARMv6(Label* label) {
   2281   ASSERT(!label->IsBound());
   2282   intptr_t bound_pc = buffer_.Size();
   2283   while (label->IsLinked()) {
   2284     const int32_t position = label->Position();
   2285     int32_t dest = bound_pc - position;
   2286     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
   2287       // Far branches are enabled and we can't encode the branch offset.
   2288 
   2289       // Grab instructions that load the offset.
   2290       const int32_t mov =
   2291           buffer_.Load<int32_t>(position);
   2292       const int32_t or1 =
   2293           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
   2294       const int32_t or2 =
   2295           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
   2296       const int32_t or3 =
   2297           buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
   2298 
   2299       // Change from relative to the branch to relative to the assembler
   2300       // buffer.
   2301       dest = buffer_.Size();
   2302       const int32_t dest0 = (dest & 0x000000ff);
   2303       const int32_t dest1 = (dest & 0x0000ff00) >> 8;
   2304       const int32_t dest2 = (dest & 0x00ff0000) >> 16;
   2305       const int32_t dest3 = (dest & 0xff000000) >> 24;
   2306       const int32_t patched_mov = 0xe3a0c400 | dest3;
   2307       const int32_t patched_or1 = 0xe38cc800 | dest2;
   2308       const int32_t patched_or2 = 0xe38ccc00 | dest1;
   2309       const int32_t patched_or3 = 0xe38cc000 | dest0;
   2310 
   2311       // Rewrite the instructions.
   2312       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov);
   2313       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1);
   2314       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2);
   2315       buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3);
   2316       label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
   2317     } else if (use_far_branches() && CanEncodeBranchOffset(dest)) {
   2318       // Grab instructions that load the offset, and the branch.
   2319       const int32_t mov =
   2320           buffer_.Load<int32_t>(position);
   2321       const int32_t or1 =
   2322           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
   2323       const int32_t or2 =
   2324           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
   2325       const int32_t or3 =
   2326           buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
   2327       const int32_t branch =
   2328           buffer_.Load<int32_t>(position + 4 * Instr::kInstrSize);
   2329 
   2330       // Grab the branch condition, and encode the link bit.
   2331       const int32_t cond = branch & 0xf0000000;
   2332       const int32_t link = (branch & 0x20) << 19;
   2333 
   2334       // Encode the branch and the offset.
   2335       const int32_t new_branch = cond | link | 0x0a000000;
   2336       const int32_t encoded = EncodeBranchOffset(dest, new_branch);
   2337 
   2338       // Write the encoded branch instruction followed by two nops.
   2339       buffer_.Store<int32_t>(position, encoded);
   2340       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
   2341           Instr::kNopInstruction);
   2342       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
   2343           Instr::kNopInstruction);
   2344       buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize,
   2345           Instr::kNopInstruction);
   2346       buffer_.Store<int32_t>(position + 4 * Instr::kInstrSize,
   2347           Instr::kNopInstruction);
   2348 
   2349       label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
   2350     } else {
   2351       int32_t next = buffer_.Load<int32_t>(position);
   2352       int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
   2353       buffer_.Store<int32_t>(position, encoded);
   2354       label->position_ = Assembler::DecodeBranchOffset(next);
   2355     }
   2356   }
   2357   label->BindTo(bound_pc);
   2358 }
   2359 
   2360 #if 0
   2361 // Moved to ARM32::AssemblerARM32::bind(Label* Label)
   2362 // Note: Most of this code isn't needed because instruction selection has
   2363 // already been handler
   2364 void Assembler::BindARMv7(Label* label) {
   2365   ASSERT(!label->IsBound());
   2366   intptr_t bound_pc = buffer_.Size();
   2367   while (label->IsLinked()) {
   2368     const int32_t position = label->Position();
   2369     int32_t dest = bound_pc - position;
   2370     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
   2371       // Far branches are enabled and we can't encode the branch offset.
   2372 
   2373       // Grab instructions that load the offset.
   2374       const int32_t movw =
   2375           buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
   2376       const int32_t movt =
   2377           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
   2378 
   2379       // Change from relative to the branch to relative to the assembler
   2380       // buffer.
   2381       dest = buffer_.Size();
   2382       const uint16_t dest_high = Utils::High16Bits(dest);
   2383       const uint16_t dest_low = Utils::Low16Bits(dest);
   2384       const int32_t patched_movt =
   2385           0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
   2386       const int32_t patched_movw =
   2387           0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
   2388 
   2389       // Rewrite the instructions.
   2390       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_movw);
   2391       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt);
   2392       label->position_ = DecodeARMv7LoadImmediate(movt, movw);
   2393     } else if (use_far_branches() && CanEncodeBranchOffset(dest)) {
   2394       // Far branches are enabled, but we can encode the branch offset.
   2395 
   2396       // Grab instructions that load the offset, and the branch.
   2397       const int32_t movw =
   2398           buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
   2399       const int32_t movt =
   2400           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
   2401       const int32_t branch =
   2402           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
   2403 
   2404       // Grab the branch condition, and encode the link bit.
   2405       const int32_t cond = branch & 0xf0000000;
   2406       const int32_t link = (branch & 0x20) << 19;
   2407 
   2408       // Encode the branch and the offset.
   2409       const int32_t new_branch = cond | link | 0x0a000000;
   2410       const int32_t encoded = EncodeBranchOffset(dest, new_branch);
   2411 
   2412       // Write the encoded branch instruction followed by two nops.
   2413       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
   2414           encoded);
   2415       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
   2416           Instr::kNopInstruction);
   2417       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
   2418           Instr::kNopInstruction);
   2419 
   2420       label->position_ = DecodeARMv7LoadImmediate(movt, movw);
   2421     } else {
   2422       int32_t next = buffer_.Load<int32_t>(position);
   2423       int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
   2424       buffer_.Store<int32_t>(position, encoded);
   2425       label->position_ = Assembler::DecodeBranchOffset(next);
   2426     }
   2427   }
   2428   label->BindTo(bound_pc);
   2429 }
   2430 #endif
   2431 
   2432 
   2433 void Assembler::Bind(Label* label) {
   2434   const ARMVersion version = TargetCPUFeatures::arm_version();
   2435   if ((version == ARMv5TE) || (version == ARMv6)) {
   2436     BindARMv6(label);
   2437   } else {
   2438     ASSERT(version == ARMv7);
   2439     BindARMv7(label);
   2440   }
   2441 }
   2442 
   2443 
   2444 OperandSize Address::OperandSizeFor(intptr_t cid) {
   2445   switch (cid) {
   2446     case kArrayCid:
   2447     case kImmutableArrayCid:
   2448       return kWord;
   2449     case kOneByteStringCid:
   2450     case kExternalOneByteStringCid:
   2451       return kByte;
   2452     case kTwoByteStringCid:
   2453     case kExternalTwoByteStringCid:
   2454       return kHalfword;
   2455     case kTypedDataInt8ArrayCid:
   2456       return kByte;
   2457     case kTypedDataUint8ArrayCid:
   2458     case kTypedDataUint8ClampedArrayCid:
   2459     case kExternalTypedDataUint8ArrayCid:
   2460     case kExternalTypedDataUint8ClampedArrayCid:
   2461       return kUnsignedByte;
   2462     case kTypedDataInt16ArrayCid:
   2463       return kHalfword;
   2464     case kTypedDataUint16ArrayCid:
   2465       return kUnsignedHalfword;
   2466     case kTypedDataInt32ArrayCid:
   2467       return kWord;
   2468     case kTypedDataUint32ArrayCid:
   2469       return kUnsignedWord;
   2470     case kTypedDataInt64ArrayCid:
   2471     case kTypedDataUint64ArrayCid:
   2472       UNREACHABLE();
   2473       return kByte;
   2474     case kTypedDataFloat32ArrayCid:
   2475       return kSWord;
   2476     case kTypedDataFloat64ArrayCid:
   2477       return kDWord;
   2478     case kTypedDataFloat32x4ArrayCid:
   2479     case kTypedDataInt32x4ArrayCid:
   2480     case kTypedDataFloat64x2ArrayCid:
   2481       return kRegList;
   2482     case kTypedDataInt8ArrayViewCid:
   2483       UNREACHABLE();
   2484       return kByte;
   2485     default:
   2486       UNREACHABLE();
   2487       return kByte;
   2488   }
   2489 }
   2490 
   2491 
   2492 bool Address::CanHoldLoadOffset(OperandSize size,
   2493                                 int32_t offset,
   2494                                 int32_t* offset_mask) {
   2495   switch (size) {
   2496     case kByte:
   2497     case kHalfword:
   2498     case kUnsignedHalfword:
   2499     case kWordPair: {
   2500       *offset_mask = 0xff;
   2501       return Utils::IsAbsoluteUint(8, offset);  // Addressing mode 3.
   2502     }
   2503     case kUnsignedByte:
   2504     case kWord:
   2505     case kUnsignedWord: {
   2506       *offset_mask = 0xfff;
   2507       return Utils::IsAbsoluteUint(12, offset);  // Addressing mode 2.
   2508     }
   2509     case kSWord:
   2510     case kDWord: {
   2511       *offset_mask = 0x3fc;  // Multiple of 4.
   2512       // VFP addressing mode.
   2513       return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
   2514     }
   2515     case kRegList: {
   2516       *offset_mask = 0x0;
   2517       return offset == 0;
   2518     }
   2519     default: {
   2520       UNREACHABLE();
   2521       return false;
   2522     }
   2523   }
   2524 }
   2525 
   2526 
   2527 bool Address::CanHoldStoreOffset(OperandSize size,
   2528                                  int32_t offset,
   2529                                  int32_t* offset_mask) {
   2530   switch (size) {
   2531     case kHalfword:
   2532     case kUnsignedHalfword:
   2533     case kWordPair: {
   2534       *offset_mask = 0xff;
   2535       return Utils::IsAbsoluteUint(8, offset);  // Addressing mode 3.
   2536     }
   2537     case kByte:
   2538     case kUnsignedByte:
   2539     case kWord:
   2540     case kUnsignedWord: {
   2541       *offset_mask = 0xfff;
   2542       return Utils::IsAbsoluteUint(12, offset);  // Addressing mode 2.
   2543     }
   2544     case kSWord:
   2545     case kDWord: {
   2546       *offset_mask = 0x3fc;  // Multiple of 4.
   2547       // VFP addressing mode.
   2548       return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
   2549     }
   2550     case kRegList: {
   2551       *offset_mask = 0x0;
   2552       return offset == 0;
   2553     }
   2554     default: {
   2555       UNREACHABLE();
   2556       return false;
   2557     }
   2558   }
   2559 }
   2560 
   2561 
   2562 bool Address::CanHoldImmediateOffset(
   2563     bool is_load, intptr_t cid, int64_t offset) {
   2564   int32_t offset_mask = 0;
   2565   if (is_load) {
   2566     return CanHoldLoadOffset(OperandSizeFor(cid), offset, &offset_mask);
   2567   } else {
   2568     return CanHoldStoreOffset(OperandSizeFor(cid), offset, &offset_mask);
   2569   }
   2570 }
   2571 
   2572 #if 0
   2573 // Moved to ARM32::AssemblerARM32::push().
   2574 void Assembler::Push(Register rd, Condition cond) {
   2575   str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
   2576 }
   2577 
   2578 // Moved to ARM32::AssemblerARM32::pop().
   2579 void Assembler::Pop(Register rd, Condition cond) {
   2580   ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond);
   2581 }
   2582 
   2583 // Moved to ARM32::AssemblerARM32::pushList().
   2584 void Assembler::PushList(RegList regs, Condition cond) {
   2585   stm(DB_W, SP, regs, cond);
   2586 }
   2587 
   2588 // Moved to ARM32::AssemblerARM32::popList().
   2589 void Assembler::PopList(RegList regs, Condition cond) {
   2590   ldm(IA_W, SP, regs, cond);
   2591 }
   2592 #endif
   2593 
   2594 void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
   2595   if (rd != rm) {
   2596     mov(rd, Operand(rm), cond);
   2597   }
   2598 }
   2599 
   2600 #if 0
   2601 // Moved to ARM32::AssemblerARM32::lsl()
   2602 void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
   2603                     Condition cond) {
   2604   ASSERT(shift_imm.type() == 1);
   2605   ASSERT(shift_imm.encoding() != 0);  // Do not use Lsl if no shift is wanted.
   2606   mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond);
   2607 }
   2608 
   2609 // Moved to ARM32::AssemblerARM32::lsl()
   2610 void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
   2611   mov(rd, Operand(rm, LSL, rs), cond);
   2612 }
   2613 
   2614 // Moved to ARM32::AssemblerARM32::lsr()
   2615 void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
   2616                     Condition cond) {
   2617   ASSERT(shift_imm.type() == 1);
   2618   uint32_t shift = shift_imm.encoding();
   2619   ASSERT(shift != 0);  // Do not use Lsr if no shift is wanted.
   2620   if (shift == 32) {
   2621     shift = 0;  // Comply to UAL syntax.
   2622   }
   2623   mov(rd, Operand(rm, LSR, shift), cond);
   2624 }
   2625 
   2626 // Moved to ARM32::AssemblerARM32::lsr()
   2627 void Assembler::Lsr(Register rd, Register rm, Register rs, Condition cond) {
   2628   mov(rd, Operand(rm, LSR, rs), cond);
   2629 }
   2630 
   2631 // Moved to ARM32::AssemblerARM32::asr()
   2632 void Assembler::Asr(Register rd, Register rm, const Operand& shift_imm,
   2633                     Condition cond) {
   2634   ASSERT(shift_imm.type() == 1);
   2635   uint32_t shift = shift_imm.encoding();
   2636   ASSERT(shift != 0);  // Do not use Asr if no shift is wanted.
   2637   if (shift == 32) {
   2638     shift = 0;  // Comply to UAL syntax.
   2639   }
   2640   mov(rd, Operand(rm, ASR, shift), cond);
   2641 }
   2642 #endif
   2643 
   2644 void Assembler::Asrs(Register rd, Register rm, const Operand& shift_imm,
   2645                      Condition cond) {
   2646   ASSERT(shift_imm.type() == 1);
   2647   uint32_t shift = shift_imm.encoding();
   2648   ASSERT(shift != 0);  // Do not use Asr if no shift is wanted.
   2649   if (shift == 32) {
   2650     shift = 0;  // Comply to UAL syntax.
   2651   }
   2652   movs(rd, Operand(rm, ASR, shift), cond);
   2653 }
   2654 
   2655 #if 0
   2656 // Moved to ARM32::AssemblerARM32::asr()
   2657 void Assembler::Asr(Register rd, Register rm, Register rs, Condition cond) {
   2658   mov(rd, Operand(rm, ASR, rs), cond);
   2659 }
   2660 #endif
   2661 
   2662 void Assembler::Ror(Register rd, Register rm, const Operand& shift_imm,
   2663                     Condition cond) {
   2664   ASSERT(shift_imm.type() == 1);
   2665   ASSERT(shift_imm.encoding() != 0);  // Use Rrx instruction.
   2666   mov(rd, Operand(rm, ROR, shift_imm.encoding()), cond);
   2667 }
   2668 
   2669 
   2670 void Assembler::Ror(Register rd, Register rm, Register rs, Condition cond) {
   2671   mov(rd, Operand(rm, ROR, rs), cond);
   2672 }
   2673 
   2674 
   2675 void Assembler::Rrx(Register rd, Register rm, Condition cond) {
   2676   mov(rd, Operand(rm, ROR, 0), cond);
   2677 }
   2678 
   2679 
   2680 void Assembler::SignFill(Register rd, Register rm, Condition cond) {
   2681   Asr(rd, rm, Operand(31), cond);
   2682 }
   2683 
   2684 
   2685 void Assembler::Vreciprocalqs(QRegister qd, QRegister qm) {
   2686   ASSERT(qm != QTMP);
   2687   ASSERT(qd != QTMP);
   2688 
   2689   // Reciprocal estimate.
   2690   vrecpeqs(qd, qm);
   2691   // 2 Newton-Raphson steps.
   2692   vrecpsqs(QTMP, qm, qd);
   2693   vmulqs(qd, qd, QTMP);
   2694   vrecpsqs(QTMP, qm, qd);
   2695   vmulqs(qd, qd, QTMP);
   2696 }
   2697 
   2698 
   2699 void Assembler::VreciprocalSqrtqs(QRegister qd, QRegister qm) {
   2700   ASSERT(qm != QTMP);
   2701   ASSERT(qd != QTMP);
   2702 
   2703   // Reciprocal square root estimate.
   2704   vrsqrteqs(qd, qm);
   2705   // 2 Newton-Raphson steps. xn+1 = xn * (3 - Q1*xn^2) / 2.
   2706   // First step.
   2707   vmulqs(QTMP, qd, qd);  // QTMP <- xn^2
   2708   vrsqrtsqs(QTMP, qm, QTMP);  // QTMP <- (3 - Q1*QTMP) / 2.
   2709   vmulqs(qd, qd, QTMP);  // xn+1 <- xn * QTMP
   2710   // Second step.
   2711   vmulqs(QTMP, qd, qd);
   2712   vrsqrtsqs(QTMP, qm, QTMP);
   2713   vmulqs(qd, qd, QTMP);
   2714 }
   2715 
   2716 
   2717 void Assembler::Vsqrtqs(QRegister qd, QRegister qm, QRegister temp) {
   2718   ASSERT(temp != QTMP);
   2719   ASSERT(qm != QTMP);
   2720   ASSERT(qd != QTMP);
   2721 
   2722   if (temp != kNoQRegister) {
   2723     vmovq(temp, qm);
   2724     qm = temp;
   2725   }
   2726 
   2727   VreciprocalSqrtqs(qd, qm);
   2728   vmovq(qm, qd);
   2729   Vreciprocalqs(qd, qm);
   2730 }
   2731 
   2732 
   2733 void Assembler::Vdivqs(QRegister qd, QRegister qn, QRegister qm) {
   2734   ASSERT(qd != QTMP);
   2735   ASSERT(qn != QTMP);
   2736   ASSERT(qm != QTMP);
   2737 
   2738   Vreciprocalqs(qd, qm);
   2739   vmulqs(qd, qn, qd);
   2740 }
   2741 
   2742 
   2743 void Assembler::Branch(const StubEntry& stub_entry,
   2744                        Patchability patchable,
   2745                        Register pp,
   2746                        Condition cond) {
   2747   const Code& target_code = Code::Handle(stub_entry.code());
   2748   const int32_t offset = ObjectPool::element_offset(
   2749       object_pool_wrapper_.FindObject(target_code, patchable));
   2750   LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, pp, cond);
   2751   ldr(IP, FieldAddress(CODE_REG, Code::entry_point_offset()), cond);
   2752   bx(IP, cond);
   2753 }
   2754 
   2755 
   2756 void Assembler::BranchLink(const Code& target, Patchability patchable) {
   2757   // Make sure that class CallPattern is able to patch the label referred
   2758   // to by this code sequence.
   2759   // For added code robustness, use 'blx lr' in a patchable sequence and
   2760   // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
   2761   const int32_t offset = ObjectPool::element_offset(
   2762       object_pool_wrapper_.FindObject(target, patchable));
   2763   LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL);
   2764   ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset()));
   2765   blx(LR);  // Use blx instruction so that the return branch prediction works.
   2766 }
   2767 
   2768 
   2769 void Assembler::BranchLink(const StubEntry& stub_entry,
   2770                            Patchability patchable) {
   2771   const Code& code = Code::Handle(stub_entry.code());
   2772   BranchLink(code, patchable);
   2773 }
   2774 
   2775 
   2776 void Assembler::BranchLinkPatchable(const Code& target) {
   2777   BranchLink(target, kPatchable);
   2778 }
   2779 
   2780 
   2781 void Assembler::BranchLink(const ExternalLabel* label) {
   2782   LoadImmediate(LR, label->address());  // Target address is never patched.
   2783   blx(LR);  // Use blx instruction so that the return branch prediction works.
   2784 }
   2785 
   2786 
   2787 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
   2788   BranchLinkPatchable(Code::Handle(stub_entry.code()));
   2789 }
   2790 
   2791 
   2792 void Assembler::BranchLinkOffset(Register base, int32_t offset) {
   2793   ASSERT(base != PC);
   2794   ASSERT(base != IP);
   2795   LoadFromOffset(kWord, IP, base, offset);
   2796   blx(IP);  // Use blx instruction so that the return branch prediction works.
   2797 }
   2798 
   2799 
   2800 void Assembler::LoadPatchableImmediate(
   2801     Register rd, int32_t value, Condition cond) {
   2802   const ARMVersion version = TargetCPUFeatures::arm_version();
   2803   if ((version == ARMv5TE) || (version == ARMv6)) {
   2804     // This sequence is patched in a few places, and should remain fixed.
   2805     const uint32_t byte0 = (value & 0x000000ff);
   2806     const uint32_t byte1 = (value & 0x0000ff00) >> 8;
   2807     const uint32_t byte2 = (value & 0x00ff0000) >> 16;
   2808     const uint32_t byte3 = (value & 0xff000000) >> 24;
   2809     mov(rd, Operand(4, byte3), cond);
   2810     orr(rd, rd, Operand(8, byte2), cond);
   2811     orr(rd, rd, Operand(12, byte1), cond);
   2812     orr(rd, rd, Operand(byte0), cond);
   2813   } else {
   2814     ASSERT(version == ARMv7);
   2815     const uint16_t value_low = Utils::Low16Bits(value);
   2816     const uint16_t value_high = Utils::High16Bits(value);
   2817     movw(rd, value_low, cond);
   2818     movt(rd, value_high, cond);
   2819   }
   2820 }
   2821 
   2822 
   2823 void Assembler::LoadDecodableImmediate(
   2824     Register rd, int32_t value, Condition cond) {
   2825   const ARMVersion version = TargetCPUFeatures::arm_version();
   2826   if ((version == ARMv5TE) || (version == ARMv6)) {
   2827     if (constant_pool_allowed()) {
   2828       const int32_t offset = Array::element_offset(FindImmediate(value));
   2829       LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond);
   2830     } else {
   2831       LoadPatchableImmediate(rd, value, cond);
   2832     }
   2833   } else {
   2834     ASSERT(version == ARMv7);
   2835     movw(rd, Utils::Low16Bits(value), cond);
   2836     const uint16_t value_high = Utils::High16Bits(value);
   2837     if (value_high != 0) {
   2838       movt(rd, value_high, cond);
   2839     }
   2840   }
   2841 }
   2842 
   2843 
   2844 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
   2845   Operand o;
   2846   if (Operand::CanHold(value, &o)) {
   2847     mov(rd, o, cond);
   2848   } else if (Operand::CanHold(~value, &o)) {
   2849     mvn(rd, o, cond);
   2850   } else {
   2851     LoadDecodableImmediate(rd, value, cond);
   2852   }
   2853 }
   2854 
   2855 
   2856 void Assembler::LoadSImmediate(SRegister sd, float value, Condition cond) {
   2857   if (!vmovs(sd, value, cond)) {
   2858     const DRegister dd = static_cast<DRegister>(sd >> 1);
   2859     const int index = sd & 1;
   2860     LoadImmediate(IP, bit_cast<int32_t, float>(value), cond);
   2861     vmovdr(dd, index, IP, cond);
   2862   }
   2863 }
   2864 
   2865 
   2866 void Assembler::LoadDImmediate(DRegister dd,
   2867                                double value,
   2868                                Register scratch,
   2869                                Condition cond) {
   2870   ASSERT(scratch != PC);
   2871   ASSERT(scratch != IP);
   2872   if (!vmovd(dd, value, cond)) {
   2873     // A scratch register and IP are needed to load an arbitrary double.
   2874     ASSERT(scratch != kNoRegister);
   2875     int64_t imm64 = bit_cast<int64_t, double>(value);
   2876     LoadImmediate(IP, Utils::Low32Bits(imm64), cond);
   2877     LoadImmediate(scratch, Utils::High32Bits(imm64), cond);
   2878     vmovdrr(dd, IP, scratch, cond);
   2879   }
   2880 }
   2881 
   2882 
   2883 void Assembler::LoadFromOffset(OperandSize size,
   2884                                Register reg,
   2885                                Register base,
   2886                                int32_t offset,
   2887                                Condition cond) {
   2888   int32_t offset_mask = 0;
   2889   if (!Address::CanHoldLoadOffset(size, offset, &offset_mask)) {
   2890     ASSERT(base != IP);
   2891     AddImmediate(IP, base, offset & ~offset_mask, cond);
   2892     base = IP;
   2893     offset = offset & offset_mask;
   2894   }
   2895   switch (size) {
   2896     case kByte:
   2897       ldrsb(reg, Address(base, offset), cond);
   2898       break;
   2899     case kUnsignedByte:
   2900       ldrb(reg, Address(base, offset), cond);
   2901       break;
   2902     case kHalfword:
   2903       ldrsh(reg, Address(base, offset), cond);
   2904       break;
   2905     case kUnsignedHalfword:
   2906       ldrh(reg, Address(base, offset), cond);
   2907       break;
   2908     case kWord:
   2909       ldr(reg, Address(base, offset), cond);
   2910       break;
   2911     case kWordPair:
   2912       ldrd(reg, base, offset, cond);
   2913       break;
   2914     default:
   2915       UNREACHABLE();
   2916   }
   2917 }
   2918 
   2919 
   2920 void Assembler::StoreToOffset(OperandSize size,
   2921                               Register reg,
   2922                               Register base,
   2923                               int32_t offset,
   2924                               Condition cond) {
   2925   int32_t offset_mask = 0;
   2926   if (!Address::CanHoldStoreOffset(size, offset, &offset_mask)) {
   2927     ASSERT(reg != IP);
   2928     ASSERT(base != IP);
   2929     AddImmediate(IP, base, offset & ~offset_mask, cond);
   2930     base = IP;
   2931     offset = offset & offset_mask;
   2932   }
   2933   switch (size) {
   2934     case kByte:
   2935       strb(reg, Address(base, offset), cond);
   2936       break;
   2937     case kHalfword:
   2938       strh(reg, Address(base, offset), cond);
   2939       break;
   2940     case kWord:
   2941       str(reg, Address(base, offset), cond);
   2942       break;
   2943     case kWordPair:
   2944       strd(reg, base, offset, cond);
   2945       break;
   2946     default:
   2947       UNREACHABLE();
   2948   }
   2949 }
   2950 
   2951 
   2952 void Assembler::LoadSFromOffset(SRegister reg,
   2953                                 Register base,
   2954                                 int32_t offset,
   2955                                 Condition cond) {
   2956   int32_t offset_mask = 0;
   2957   if (!Address::CanHoldLoadOffset(kSWord, offset, &offset_mask)) {
   2958     ASSERT(base != IP);
   2959     AddImmediate(IP, base, offset & ~offset_mask, cond);
   2960     base = IP;
   2961     offset = offset & offset_mask;
   2962   }
   2963   vldrs(reg, Address(base, offset), cond);
   2964 }
   2965 
   2966 
   2967 void Assembler::StoreSToOffset(SRegister reg,
   2968                                Register base,
   2969                                int32_t offset,
   2970                                Condition cond) {
   2971   int32_t offset_mask = 0;
   2972   if (!Address::CanHoldStoreOffset(kSWord, offset, &offset_mask)) {
   2973     ASSERT(base != IP);
   2974     AddImmediate(IP, base, offset & ~offset_mask, cond);
   2975     base = IP;
   2976     offset = offset & offset_mask;
   2977   }
   2978   vstrs(reg, Address(base, offset), cond);
   2979 }
   2980 
   2981 
   2982 void Assembler::LoadDFromOffset(DRegister reg,
   2983                                 Register base,
   2984                                 int32_t offset,
   2985                                 Condition cond) {
   2986   int32_t offset_mask = 0;
   2987   if (!Address::CanHoldLoadOffset(kDWord, offset, &offset_mask)) {
   2988     ASSERT(base != IP);
   2989     AddImmediate(IP, base, offset & ~offset_mask, cond);
   2990     base = IP;
   2991     offset = offset & offset_mask;
   2992   }
   2993   vldrd(reg, Address(base, offset), cond);
   2994 }
   2995 
   2996 
   2997 void Assembler::StoreDToOffset(DRegister reg,
   2998                                Register base,
   2999                                int32_t offset,
   3000                                Condition cond) {
   3001   int32_t offset_mask = 0;
   3002   if (!Address::CanHoldStoreOffset(kDWord, offset, &offset_mask)) {
   3003     ASSERT(base != IP);
   3004     AddImmediate(IP, base, offset & ~offset_mask, cond);
   3005     base = IP;
   3006     offset = offset & offset_mask;
   3007   }
   3008   vstrd(reg, Address(base, offset), cond);
   3009 }
   3010 
   3011 
   3012 void Assembler::LoadMultipleDFromOffset(DRegister first,
   3013                                         intptr_t count,
   3014                                         Register base,
   3015                                         int32_t offset) {
   3016   ASSERT(base != IP);
   3017   AddImmediate(IP, base, offset);
   3018   vldmd(IA, IP, first, count);
   3019 }
   3020 
   3021 void Assembler::StoreMultipleDToOffset(DRegister first,
   3022                                        intptr_t count,
   3023                                        Register base,
   3024                                        int32_t offset) {
   3025   ASSERT(base != IP);
   3026   AddImmediate(IP, base, offset);
   3027   vstmd(IA, IP, first, count);
   3028 }
   3029 
   3030 
   3031 void Assembler::CopyDoubleField(
   3032     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
   3033   if (TargetCPUFeatures::vfp_supported()) {
   3034     LoadDFromOffset(dtmp, src, Double::value_offset() - kHeapObjectTag);
   3035     StoreDToOffset(dtmp, dst, Double::value_offset() - kHeapObjectTag);
   3036   } else {
   3037     LoadFromOffset(kWord, tmp1, src,
   3038         Double::value_offset() - kHeapObjectTag);
   3039     LoadFromOffset(kWord, tmp2, src,
   3040         Double::value_offset() + kWordSize - kHeapObjectTag);
   3041     StoreToOffset(kWord, tmp1, dst,
   3042         Double::value_offset() - kHeapObjectTag);
   3043     StoreToOffset(kWord, tmp2, dst,
   3044         Double::value_offset() + kWordSize - kHeapObjectTag);
   3045   }
   3046 }
   3047 
   3048 
   3049 void Assembler::CopyFloat32x4Field(
   3050     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
   3051   if (TargetCPUFeatures::neon_supported()) {
   3052     LoadMultipleDFromOffset(dtmp, 2, src,
   3053         Float32x4::value_offset() - kHeapObjectTag);
   3054     StoreMultipleDToOffset(dtmp, 2, dst,
   3055         Float32x4::value_offset() - kHeapObjectTag);
   3056   } else {
   3057     LoadFromOffset(kWord, tmp1, src,
   3058         (Float32x4::value_offset() + 0 * kWordSize) - kHeapObjectTag);
   3059     LoadFromOffset(kWord, tmp2, src,
   3060         (Float32x4::value_offset() + 1 * kWordSize) - kHeapObjectTag);
   3061     StoreToOffset(kWord, tmp1, dst,
   3062         (Float32x4::value_offset() + 0 * kWordSize) - kHeapObjectTag);
   3063     StoreToOffset(kWord, tmp2, dst,
   3064         (Float32x4::value_offset() + 1 * kWordSize) - kHeapObjectTag);
   3065 
   3066     LoadFromOffset(kWord, tmp1, src,
   3067         (Float32x4::value_offset() + 2 * kWordSize) - kHeapObjectTag);
   3068     LoadFromOffset(kWord, tmp2, src,
   3069         (Float32x4::value_offset() + 3 * kWordSize) - kHeapObjectTag);
   3070     StoreToOffset(kWord, tmp1, dst,
   3071         (Float32x4::value_offset() + 2 * kWordSize) - kHeapObjectTag);
   3072     StoreToOffset(kWord, tmp2, dst,
   3073         (Float32x4::value_offset() + 3 * kWordSize) - kHeapObjectTag);
   3074   }
   3075 }
   3076 
   3077 
   3078 void Assembler::CopyFloat64x2Field(
   3079     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
   3080   if (TargetCPUFeatures::neon_supported()) {
   3081     LoadMultipleDFromOffset(dtmp, 2, src,
   3082         Float64x2::value_offset() - kHeapObjectTag);
   3083     StoreMultipleDToOffset(dtmp, 2, dst,
   3084         Float64x2::value_offset() - kHeapObjectTag);
   3085   } else {
   3086     LoadFromOffset(kWord, tmp1, src,
   3087         (Float64x2::value_offset() + 0 * kWordSize) - kHeapObjectTag);
   3088     LoadFromOffset(kWord, tmp2, src,
   3089         (Float64x2::value_offset() + 1 * kWordSize) - kHeapObjectTag);
   3090     StoreToOffset(kWord, tmp1, dst,
   3091         (Float64x2::value_offset() + 0 * kWordSize) - kHeapObjectTag);
   3092     StoreToOffset(kWord, tmp2, dst,
   3093         (Float64x2::value_offset() + 1 * kWordSize) - kHeapObjectTag);
   3094 
   3095     LoadFromOffset(kWord, tmp1, src,
   3096         (Float64x2::value_offset() + 2 * kWordSize) - kHeapObjectTag);
   3097     LoadFromOffset(kWord, tmp2, src,
   3098         (Float64x2::value_offset() + 3 * kWordSize) - kHeapObjectTag);
   3099     StoreToOffset(kWord, tmp1, dst,
   3100         (Float64x2::value_offset() + 2 * kWordSize) - kHeapObjectTag);
   3101     StoreToOffset(kWord, tmp2, dst,
   3102         (Float64x2::value_offset() + 3 * kWordSize) - kHeapObjectTag);
   3103   }
   3104 }
   3105 
   3106 
   3107 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) {
   3108   AddImmediate(rd, rd, value, cond);
   3109 }
   3110 
   3111 
   3112 void Assembler::AddImmediate(Register rd, Register rn, int32_t value,
   3113                              Condition cond) {
   3114   if (value == 0) {
   3115     if (rd != rn) {
   3116       mov(rd, Operand(rn), cond);
   3117     }
   3118     return;
   3119   }
   3120   // We prefer to select the shorter code sequence rather than selecting add for
   3121   // positive values and sub for negatives ones, which would slightly improve
   3122   // the readability of generated code for some constants.
   3123   Operand o;
   3124   if (Operand::CanHold(value, &o)) {
   3125     add(rd, rn, o, cond);
   3126   } else if (Operand::CanHold(-value, &o)) {
   3127     sub(rd, rn, o, cond);
   3128   } else {
   3129     ASSERT(rn != IP);
   3130     if (Operand::CanHold(~value, &o)) {
   3131       mvn(IP, o, cond);
   3132       add(rd, rn, Operand(IP), cond);
   3133     } else if (Operand::CanHold(~(-value), &o)) {
   3134       mvn(IP, o, cond);
   3135       sub(rd, rn, Operand(IP), cond);
   3136     } else {
   3137       LoadDecodableImmediate(IP, value, cond);
   3138       add(rd, rn, Operand(IP), cond);
   3139     }
   3140   }
   3141 }
   3142 
   3143 
   3144 void Assembler::AddImmediateSetFlags(Register rd, Register rn, int32_t value,
   3145                                      Condition cond) {
   3146   Operand o;
   3147   if (Operand::CanHold(value, &o)) {
   3148     // Handles value == kMinInt32.
   3149     adds(rd, rn, o, cond);
   3150   } else if (Operand::CanHold(-value, &o)) {
   3151     ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
   3152     subs(rd, rn, o, cond);
   3153   } else {
   3154     ASSERT(rn != IP);
   3155     if (Operand::CanHold(~value, &o)) {
   3156       mvn(IP, o, cond);
   3157       adds(rd, rn, Operand(IP), cond);
   3158     } else if (Operand::CanHold(~(-value), &o)) {
   3159       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
   3160       mvn(IP, o, cond);
   3161       subs(rd, rn, Operand(IP), cond);
   3162     } else {
   3163       LoadDecodableImmediate(IP, value, cond);
   3164       adds(rd, rn, Operand(IP), cond);
   3165     }
   3166   }
   3167 }
   3168 
   3169 
   3170 void Assembler::SubImmediateSetFlags(Register rd, Register rn, int32_t value,
   3171                                     Condition cond) {
   3172   Operand o;
   3173   if (Operand::CanHold(value, &o)) {
   3174     // Handles value == kMinInt32.
   3175     subs(rd, rn, o, cond);
   3176   } else if (Operand::CanHold(-value, &o)) {
   3177     ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
   3178     adds(rd, rn, o, cond);
   3179   } else {
   3180     ASSERT(rn != IP);
   3181     if (Operand::CanHold(~value, &o)) {
   3182       mvn(IP, o, cond);
   3183       subs(rd, rn, Operand(IP), cond);
   3184     } else if (Operand::CanHold(~(-value), &o)) {
   3185       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
   3186       mvn(IP, o, cond);
   3187       adds(rd, rn, Operand(IP), cond);
   3188     } else {
   3189       LoadDecodableImmediate(IP, value, cond);
   3190       subs(rd, rn, Operand(IP), cond);
   3191     }
   3192   }
   3193 }
   3194 
   3195 
   3196 void Assembler::AndImmediate(Register rd, Register rs, int32_t imm,
   3197                              Condition cond) {
   3198   Operand o;
   3199   if (Operand::CanHold(imm, &o)) {
   3200     and_(rd, rs, Operand(o), cond);
   3201   } else {
   3202     LoadImmediate(TMP, imm, cond);
   3203     and_(rd, rs, Operand(TMP), cond);
   3204   }
   3205 }
   3206 
   3207 
   3208 void Assembler::CompareImmediate(Register rn, int32_t value, Condition cond) {
   3209   Operand o;
   3210   if (Operand::CanHold(value, &o)) {
   3211     cmp(rn, o, cond);
   3212   } else {
   3213     ASSERT(rn != IP);
   3214     LoadImmediate(IP, value, cond);
   3215     cmp(rn, Operand(IP), cond);
   3216   }
   3217 }
   3218 
   3219 
   3220 void Assembler::TestImmediate(Register rn, int32_t imm, Condition cond) {
   3221   Operand o;
   3222   if (Operand::CanHold(imm, &o)) {
   3223     tst(rn, o, cond);
   3224   } else {
   3225     LoadImmediate(IP, imm);
   3226     tst(rn, Operand(IP), cond);
   3227   }
   3228 }
   3229 
   3230 void Assembler::IntegerDivide(Register result, Register left, Register right,
   3231                               DRegister tmpl, DRegister tmpr) {
   3232   ASSERT(tmpl != tmpr);
   3233   if (TargetCPUFeatures::integer_division_supported()) {
   3234     sdiv(result, left, right);
   3235   } else {
   3236     ASSERT(TargetCPUFeatures::vfp_supported());
   3237     SRegister stmpl = static_cast<SRegister>(2 * tmpl);
   3238     SRegister stmpr = static_cast<SRegister>(2 * tmpr);
   3239     vmovsr(stmpl, left);
   3240     vcvtdi(tmpl, stmpl);  // left is in tmpl.
   3241     vmovsr(stmpr, right);
   3242     vcvtdi(tmpr, stmpr);  // right is in tmpr.
   3243     vdivd(tmpr, tmpl, tmpr);
   3244     vcvtid(stmpr, tmpr);
   3245     vmovrs(result, stmpr);
   3246   }
   3247 }
   3248 
   3249 
   3250 static int NumRegsBelowFP(RegList regs) {
   3251   int count = 0;
   3252   for (int i = 0; i < FP; i++) {
   3253     if ((regs & (1 << i)) != 0) {
   3254       count++;
   3255     }
   3256   }
   3257   return count;
   3258 }
   3259 
   3260 
   3261 void Assembler::EnterFrame(RegList regs, intptr_t frame_size) {
   3262   if (prologue_offset_ == -1) {
   3263     prologue_offset_ = CodeSize();
   3264   }
   3265   PushList(regs);
   3266   if ((regs & (1 << FP)) != 0) {
   3267     // Set FP to the saved previous FP.
   3268     add(FP, SP, Operand(4 * NumRegsBelowFP(regs)));
   3269   }
   3270   AddImmediate(SP, -frame_size);
   3271 }
   3272 
   3273 
   3274 void Assembler::LeaveFrame(RegList regs) {
   3275   ASSERT((regs & (1 << PC)) == 0);  // Must not pop PC.
   3276   if ((regs & (1 << FP)) != 0) {
   3277     // Use FP to set SP.
   3278     sub(SP, FP, Operand(4 * NumRegsBelowFP(regs)));
   3279   }
   3280   PopList(regs);
   3281 }
   3282 
   3283 
   3284 void Assembler::Ret() {
   3285   bx(LR);
   3286 }
   3287 
   3288 
   3289 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
   3290   // Reserve space for arguments and align frame before entering
   3291   // the C++ world.
   3292   AddImmediate(SP, -frame_space);
   3293   if (OS::ActivationFrameAlignment() > 1) {
   3294     bic(SP, SP, Operand(OS::ActivationFrameAlignment() - 1));
   3295   }
   3296 }
   3297 
   3298 
   3299 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) {
   3300   // Preserve volatile CPU registers and PP.
   3301   EnterFrame(kDartVolatileCpuRegs | (1 << PP) | (1 << FP), 0);
   3302   COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
   3303 
   3304   // Preserve all volatile FPU registers.
   3305   if (TargetCPUFeatures::vfp_supported()) {
   3306     DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
   3307     DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
   3308     if ((lastv - firstv + 1) >= 16) {
   3309       DRegister mid = static_cast<DRegister>(firstv + 16);
   3310       vstmd(DB_W, SP, mid, lastv - mid + 1);
   3311       vstmd(DB_W, SP, firstv, 16);
   3312     } else {
   3313       vstmd(DB_W, SP, firstv, lastv - firstv + 1);
   3314     }
   3315   }
   3316 
   3317   LoadPoolPointer();
   3318 
   3319   ReserveAlignedFrameSpace(frame_space);
   3320 }
   3321 
   3322 
   3323 void Assembler::LeaveCallRuntimeFrame() {
   3324   // SP might have been modified to reserve space for arguments
   3325   // and ensure proper alignment of the stack frame.
   3326   // We need to restore it before restoring registers.
   3327   const intptr_t kPushedFpuRegisterSize =
   3328       TargetCPUFeatures::vfp_supported() ?
   3329       kDartVolatileFpuRegCount * kFpuRegisterSize : 0;
   3330 
   3331   COMPILE_ASSERT(PP < FP);
   3332   COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
   3333   // kVolatileCpuRegCount +1 for PP, -1 because even though LR is volatile,
   3334   // it is pushed ahead of FP.
   3335   const intptr_t kPushedRegistersSize =
   3336       kDartVolatileCpuRegCount * kWordSize + kPushedFpuRegisterSize;
   3337   AddImmediate(SP, FP, -kPushedRegistersSize);
   3338 
   3339   // Restore all volatile FPU registers.
   3340   if (TargetCPUFeatures::vfp_supported()) {
   3341     DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
   3342     DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
   3343     if ((lastv - firstv + 1) >= 16) {
   3344       DRegister mid = static_cast<DRegister>(firstv + 16);
   3345       vldmd(IA_W, SP, firstv, 16);
   3346       vldmd(IA_W, SP, mid, lastv - mid + 1);
   3347     } else {
   3348       vldmd(IA_W, SP, firstv, lastv - firstv + 1);
   3349     }
   3350   }
   3351 
   3352   // Restore volatile CPU registers.
   3353   LeaveFrame(kDartVolatileCpuRegs | (1 << PP) | (1 << FP));
   3354 }
   3355 
   3356 
   3357 void Assembler::CallRuntime(const RuntimeEntry& entry,
   3358                             intptr_t argument_count) {
   3359   entry.Call(this, argument_count);
   3360 }
   3361 
   3362 
   3363 void Assembler::EnterDartFrame(intptr_t frame_size) {
   3364   ASSERT(!constant_pool_allowed());
   3365 
   3366   // Registers are pushed in descending order: R9 | R10 | R11 | R14.
   3367   EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << LR), 0);
   3368 
   3369   // Setup pool pointer for this dart function.
   3370   LoadPoolPointer();
   3371 
   3372   // Reserve space for locals.
   3373   AddImmediate(SP, -frame_size);
   3374 }
   3375 
   3376 
   3377 // On entry to a function compiled for OSR, the caller's frame pointer, the
   3378 // stack locals, and any copied parameters are already in place.  The frame
   3379 // pointer is already set up.  The PC marker is not correct for the
   3380 // optimized function and there may be extra space for spill slots to
   3381 // allocate. We must also set up the pool pointer for the function.
   3382 void Assembler::EnterOsrFrame(intptr_t extra_size) {
   3383   ASSERT(!constant_pool_allowed());
   3384   Comment("EnterOsrFrame");
   3385   RestoreCodePointer();
   3386   LoadPoolPointer();
   3387 
   3388   AddImmediate(SP, -extra_size);
   3389 }
   3390 
   3391 
   3392 void Assembler::LeaveDartFrame(RestorePP restore_pp) {
   3393   if (restore_pp == kRestoreCallerPP) {
   3394     ldr(PP, Address(FP, kSavedCallerPpSlotFromFp * kWordSize));
   3395     set_constant_pool_allowed(false);
   3396   }
   3397   Drop(2);  // Drop saved PP, PC marker.
   3398   LeaveFrame((1 << FP) | (1 << LR));
   3399 }
   3400 
   3401 
   3402 void Assembler::EnterStubFrame() {
   3403   EnterDartFrame(0);
   3404 }
   3405 
   3406 
   3407 void Assembler::LeaveStubFrame() {
   3408   LeaveDartFrame();
   3409 }
   3410 
   3411 
   3412 void Assembler::LoadAllocationStatsAddress(Register dest,
   3413                                            intptr_t cid,
   3414                                            bool inline_isolate) {
   3415   ASSERT(dest != kNoRegister);
   3416   ASSERT(dest != TMP);
   3417   ASSERT(cid > 0);
   3418   const intptr_t class_offset = ClassTable::ClassOffsetFor(cid);
   3419   if (inline_isolate) {
   3420     ASSERT(FLAG_allow_absolute_addresses);
   3421     ClassTable* class_table = Isolate::Current()->class_table();
   3422     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
   3423     if (cid < kNumPredefinedCids) {
   3424       LoadImmediate(dest, reinterpret_cast<uword>(*table_ptr) + class_offset);
   3425     } else {
   3426       LoadImmediate(dest, reinterpret_cast<uword>(table_ptr));
   3427       ldr(dest, Address(dest, 0));
   3428       AddImmediate(dest, class_offset);
   3429     }
   3430   } else {
   3431     LoadIsolate(dest);
   3432     intptr_t table_offset =
   3433         Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
   3434     ldr(dest, Address(dest, table_offset));
   3435     AddImmediate(dest, class_offset);
   3436   }
   3437 }
   3438 
   3439 
   3440 void Assembler::MaybeTraceAllocation(intptr_t cid,
   3441                                      Register temp_reg,
   3442                                      Label* trace,
   3443                                      bool inline_isolate) {
   3444   LoadAllocationStatsAddress(temp_reg, cid, inline_isolate);
   3445   const uword state_offset = ClassHeapStats::state_offset();
   3446   ldr(temp_reg, Address(temp_reg, state_offset));
   3447   tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
   3448   b(trace, NE);
   3449 }
   3450 
   3451 
   3452 void Assembler::IncrementAllocationStats(Register stats_addr_reg,
   3453                                          intptr_t cid,
   3454                                          Heap::Space space) {
   3455   ASSERT(stats_addr_reg != kNoRegister);
   3456   ASSERT(stats_addr_reg != TMP);
   3457   ASSERT(cid > 0);
   3458   const uword count_field_offset = (space == Heap::kNew) ?
   3459     ClassHeapStats::allocated_since_gc_new_space_offset() :
   3460     ClassHeapStats::allocated_since_gc_old_space_offset();
   3461   const Address& count_address = Address(stats_addr_reg, count_field_offset);
   3462   ldr(TMP, count_address);
   3463   AddImmediate(TMP, 1);
   3464   str(TMP, count_address);
   3465 }
   3466 
   3467 
   3468 void Assembler::IncrementAllocationStatsWithSize(Register stats_addr_reg,
   3469                                                  Register size_reg,
   3470                                                  Heap::Space space) {
   3471   ASSERT(stats_addr_reg != kNoRegister);
   3472   ASSERT(stats_addr_reg != TMP);
   3473   const uword count_field_offset = (space == Heap::kNew) ?
   3474     ClassHeapStats::allocated_since_gc_new_space_offset() :
   3475     ClassHeapStats::allocated_since_gc_old_space_offset();
   3476   const uword size_field_offset = (space == Heap::kNew) ?
   3477     ClassHeapStats::allocated_size_since_gc_new_space_offset() :
   3478     ClassHeapStats::allocated_size_since_gc_old_space_offset();
   3479   const Address& count_address = Address(stats_addr_reg, count_field_offset);
   3480   const Address& size_address = Address(stats_addr_reg, size_field_offset);
   3481   ldr(TMP, count_address);
   3482   AddImmediate(TMP, 1);
   3483   str(TMP, count_address);
   3484   ldr(TMP, size_address);
   3485   add(TMP, TMP, Operand(size_reg));
   3486   str(TMP, size_address);
   3487 }
   3488 
   3489 
   3490 void Assembler::TryAllocate(const Class& cls,
   3491                             Label* failure,
   3492                             Register instance_reg,
   3493                             Register temp_reg) {
   3494   ASSERT(failure != NULL);
   3495   if (FLAG_inline_alloc) {
   3496     ASSERT(instance_reg != temp_reg);
   3497     ASSERT(temp_reg != IP);
   3498     const intptr_t instance_size = cls.instance_size();
   3499     ASSERT(instance_size != 0);
   3500     // If this allocation is traced, program will jump to failure path
   3501     // (i.e. the allocation stub) which will allocate the object and trace the
   3502     // allocation call site.
   3503     MaybeTraceAllocation(cls.id(), temp_reg, failure,
   3504                          /* inline_isolate = */ false);
   3505     Heap::Space space = Heap::SpaceForAllocation(cls.id());
   3506     ldr(temp_reg, Address(THR, Thread::heap_offset()));
   3507     ldr(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
   3508     // TODO(koda): Protect against unsigned overflow here.
   3509     AddImmediateSetFlags(instance_reg, instance_reg, instance_size);
   3510 
   3511     // instance_reg: potential next object start.
   3512     ldr(IP, Address(temp_reg, Heap::EndOffset(space)));
   3513     cmp(IP, Operand(instance_reg));
   3514     // fail if heap end unsigned less than or equal to instance_reg.
   3515     b(failure, LS);
   3516 
   3517     // Successfully allocated the object, now update top to point to
   3518     // next object start and store the class in the class field of object.
   3519     str(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
   3520 
   3521     LoadAllocationStatsAddress(temp_reg, cls.id(),
   3522                                /* inline_isolate = */ false);
   3523 
   3524     ASSERT(instance_size >= kHeapObjectTag);
   3525     AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
   3526 
   3527     uword tags = 0;
   3528     tags = RawObject::SizeTag::update(instance_size, tags);
   3529     ASSERT(cls.id() != kIllegalCid);
   3530     tags = RawObject::ClassIdTag::update(cls.id(), tags);
   3531     LoadImmediate(IP, tags);
   3532     str(IP, FieldAddress(instance_reg, Object::tags_offset()));
   3533 
   3534     IncrementAllocationStats(temp_reg, cls.id(), space);
   3535   } else {
   3536     b(failure);
   3537   }
   3538 }
   3539 
   3540 
   3541 void Assembler::TryAllocateArray(intptr_t cid,
   3542                                  intptr_t instance_size,
   3543                                  Label* failure,
   3544                                  Register instance,
   3545                                  Register end_address,
   3546                                  Register temp1,
   3547                                  Register temp2) {
   3548   if (FLAG_inline_alloc) {
   3549     // If this allocation is traced, program will jump to failure path
   3550     // (i.e. the allocation stub) which will allocate the object and trace the
   3551     // allocation call site.
   3552     MaybeTraceAllocation(cid, temp1, failure, /* inline_isolate = */ false);
   3553     Heap::Space space = Heap::SpaceForAllocation(cid);
   3554     ldr(temp1, Address(THR, Thread::heap_offset()));
   3555     // Potential new object start.
   3556     ldr(instance, Address(temp1, Heap::TopOffset(space)));
   3557     AddImmediateSetFlags(end_address, instance, instance_size);
   3558     b(failure, CS);  // Branch if unsigned overflow.
   3559 
   3560     // Check if the allocation fits into the remaining space.
   3561     // instance: potential new object start.
   3562     // end_address: potential next object start.
   3563     ldr(temp2, Address(temp1, Heap::EndOffset(space)));
   3564     cmp(end_address, Operand(temp2));
   3565     b(failure, CS);
   3566 
   3567     LoadAllocationStatsAddress(temp2, cid, /* inline_isolate = */ false);
   3568 
   3569     // Successfully allocated the object(s), now update top to point to
   3570     // next object start and initialize the object.
   3571     str(end_address, Address(temp1, Heap::TopOffset(space)));
   3572     add(instance, instance, Operand(kHeapObjectTag));
   3573 
   3574     // Initialize the tags.
   3575     // instance: new object start as a tagged pointer.
   3576     uword tags = 0;
   3577     tags = RawObject::ClassIdTag::update(cid, tags);
   3578     tags = RawObject::SizeTag::update(instance_size, tags);
   3579     LoadImmediate(temp1, tags);
   3580     str(temp1, FieldAddress(instance, Array::tags_offset()));  // Store tags.
   3581 
   3582     LoadImmediate(temp1, instance_size);
   3583     IncrementAllocationStatsWithSize(temp2, temp1, space);
   3584   } else {
   3585     b(failure);
   3586   }
   3587 }
   3588 
   3589 
   3590 void Assembler::Stop(const char* message) {
   3591   if (FLAG_print_stop_message) {
   3592     PushList((1 << R0) | (1 << IP) | (1 << LR));  // Preserve R0, IP, LR.
   3593     LoadImmediate(R0, reinterpret_cast<int32_t>(message));
   3594     // PrintStopMessage() preserves all registers.
   3595     BranchLink(&StubCode::PrintStopMessage_entry()->label());
   3596     PopList((1 << R0) | (1 << IP) | (1 << LR));  // Restore R0, IP, LR.
   3597   }
   3598   // Emit the message address before the svc instruction, so that we can
   3599   // 'unstop' and continue execution in the simulator or jump to the next
   3600   // instruction in gdb.
   3601   Label stop;
   3602   b(&stop);
   3603   Emit(reinterpret_cast<int32_t>(message));
   3604   Bind(&stop);
   3605   bkpt(Instr::kStopMessageCode);
   3606 }
   3607 
   3608 
   3609 Address Assembler::ElementAddressForIntIndex(bool is_load,
   3610                                              bool is_external,
   3611                                              intptr_t cid,
   3612                                              intptr_t index_scale,
   3613                                              Register array,
   3614                                              intptr_t index,
   3615                                              Register temp) {
   3616   const int64_t offset_base =
   3617       (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
   3618   const int64_t offset = offset_base +
   3619       static_cast<int64_t>(index) * index_scale;
   3620   ASSERT(Utils::IsInt(32, offset));
   3621 
   3622   if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
   3623     return Address(array, static_cast<int32_t>(offset));
   3624   } else {
   3625     ASSERT(Address::CanHoldImmediateOffset(is_load, cid, offset - offset_base));
   3626     AddImmediate(temp, array, static_cast<int32_t>(offset_base));
   3627     return Address(temp, static_cast<int32_t>(offset - offset_base));
   3628   }
   3629 }
   3630 
   3631 
   3632 Address Assembler::ElementAddressForRegIndex(bool is_load,
   3633                                              bool is_external,
   3634                                              intptr_t cid,
   3635                                              intptr_t index_scale,
   3636                                              Register array,
   3637                                              Register index) {
   3638   // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
   3639   const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
   3640   int32_t offset =
   3641       is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
   3642   const OperandSize size = Address::OperandSizeFor(cid);
   3643   ASSERT(array != IP);
   3644   ASSERT(index != IP);
   3645   const Register base = is_load ? IP : index;
   3646   if ((offset != 0) ||
   3647       (size == kSWord) || (size == kDWord) || (size == kRegList)) {
   3648     if (shift < 0) {
   3649       ASSERT(shift == -1);
   3650       add(base, array, Operand(index, ASR, 1));
   3651     } else {
   3652       add(base, array, Operand(index, LSL, shift));
   3653     }
   3654   } else {
   3655     if (shift < 0) {
   3656       ASSERT(shift == -1);
   3657       return Address(array, index, ASR, 1);
   3658     } else {
   3659       return Address(array, index, LSL, shift);
   3660     }
   3661   }
   3662   int32_t offset_mask = 0;
   3663   if ((is_load && !Address::CanHoldLoadOffset(size,
   3664                                               offset,
   3665                                               &offset_mask)) ||
   3666       (!is_load && !Address::CanHoldStoreOffset(size,
   3667                                                 offset,
   3668                                                 &offset_mask))) {
   3669     AddImmediate(base, offset & ~offset_mask);
   3670     offset = offset & offset_mask;
   3671   }
   3672   return Address(base, offset);
   3673 }
   3674 
   3675 
   3676 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   3677   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
   3678   "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
   3679 };
   3680 
   3681 
   3682 const char* Assembler::RegisterName(Register reg) {
   3683   ASSERT((0 <= reg) && (reg < kNumberOfCpuRegisters));
   3684   return cpu_reg_names[reg];
   3685 }
   3686 
   3687 
   3688 static const char* fpu_reg_names[kNumberOfFpuRegisters] = {
   3689   "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
   3690 #if defined(VFPv3_D32)
   3691   "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
   3692 #endif
   3693 };
   3694 
   3695 
   3696 const char* Assembler::FpuRegisterName(FpuRegister reg) {
   3697   ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters));
   3698   return fpu_reg_names[reg];
   3699 }
   3700 
   3701 }  // namespace dart
   3702 
   3703 #endif  // defined TARGET_ARCH_ARM
   3704