12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/*
22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project
32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License.
62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at
72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software
112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and
142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License.
152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */
16a5d5cfda6239d8876937e75eba43222f639d2447Carl Shapiro
172c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#include "assembler_arm.h"
182c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
197cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe#include <algorithm>
207cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe
2180afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "base/bit_utils.h"
2207ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h"
23166db04e259ca51838c311891598664deeed85adIan Rogers#include "entrypoints/quick/quick_entrypoints.h"
24578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "offsets.h"
25e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro#include "thread.h"
26a5d5cfda6239d8876937e75eba43222f639d2447Carl Shapiro
276b6b5f0e67ce03f38223a525612955663bc1799bCarl Shapironamespace art {
282c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersnamespace arm {
29a5d5cfda6239d8876937e75eba43222f639d2447Carl Shapiro
3065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonconst char* kRegisterNames[] = {
311f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
321f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  "fp", "ip", "sp", "lr", "pc"
331f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes};
3465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
3565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonconst char* kConditionNames[] = {
3665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT",
3765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  "LE", "AL",
3865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison};
3965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
401f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughesstd::ostream& operator<<(std::ostream& os, const Register& rhs) {
411f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  if (rhs >= R0 && rhs <= PC) {
421f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes    os << kRegisterNames[rhs];
431f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  } else {
44b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "Register[" << static_cast<int>(rhs) << "]";
451f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  }
461f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  return os;
471f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes}
481f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
491f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
501f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughesstd::ostream& operator<<(std::ostream& os, const SRegister& rhs) {
511f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  if (rhs >= S0 && rhs < kNumberOfSRegisters) {
52b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "s" << static_cast<int>(rhs);
531f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  } else {
54b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "SRegister[" << static_cast<int>(rhs) << "]";
551f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  }
561f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  return os;
571f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes}
581f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
591f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
601f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughesstd::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
611f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  if (rhs >= D0 && rhs < kNumberOfDRegisters) {
62b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "d" << static_cast<int>(rhs);
631f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  } else {
64b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "DRegister[" << static_cast<int>(rhs) << "]";
651f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  }
661f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  return os;
671f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes}
681f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
691f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughesstd::ostream& operator<<(std::ostream& os, const Condition& rhs) {
701f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  if (rhs >= EQ && rhs <= AL) {
711f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes    os << kConditionNames[rhs];
721f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  } else {
73b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    os << "Condition[" << static_cast<int>(rhs) << "]";
741f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  }
751f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes  return os;
761f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes}
771f359b08f5ad33ae72e4073b86a9257fe1ed11e5Elliott Hughes
7896f89a290eb67d7bf4b1636798fa28df14309cc7Nicolas GeoffrayShifterOperand::ShifterOperand(uint32_t immed)
7996f89a290eb67d7bf4b1636798fa28df14309cc7Nicolas Geoffray    : type_(kImmediate), rm_(kNoRegister), rs_(kNoRegister),
8096f89a290eb67d7bf4b1636798fa28df14309cc7Nicolas Geoffray      is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(immed) {
8196f89a290eb67d7bf4b1636798fa28df14309cc7Nicolas Geoffray  CHECK(immed < (1u << 12) || ArmAssembler::ModifiedImmediate(immed) != kInvalidModifiedImmediate);
8296f89a290eb67d7bf4b1636798fa28df14309cc7Nicolas Geoffray}
83a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro
84a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro
8565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t ShifterOperand::encodingArm() const {
8665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  CHECK(is_valid());
8765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  switch (type_) {
8865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kImmediate:
8965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      if (is_rotate_) {
9065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        return (rotate_ << kRotateShift) | (immed_ << kImmed8Shift);
9165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      } else {
9265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        return immed_;
9365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      }
9465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kRegister:
9565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      if (is_shift_) {
96849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe        uint32_t shift_type;
97849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe        switch (shift_) {
98849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe          case arm::Shift::ROR:
99849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            shift_type = static_cast<uint32_t>(shift_);
100849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            CHECK_NE(immed_, 0U);
101849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            break;
102849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe          case arm::Shift::RRX:
103849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            shift_type = static_cast<uint32_t>(arm::Shift::ROR);  // Same encoding as ROR.
104849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            CHECK_EQ(immed_, 0U);
105849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            break;
106849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe          default:
107849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe            shift_type = static_cast<uint32_t>(shift_);
108849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe        }
10965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        // Shifted immediate or register.
11065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        if (rs_ == kNoRegister) {
11165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          // Immediate shift.
11265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          return immed_ << kShiftImmShift |
113849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe                          shift_type << kShiftShift |
11465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison                          static_cast<uint32_t>(rm_);
11565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        } else {
11665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          // Register shift.
11765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          return static_cast<uint32_t>(rs_) << kShiftRegisterShift |
118849cc5e54cbd05f4efbd6082e03547ed9284639fAndreas Gampe              shift_type << kShiftShift | (1 << 4) |
11965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison              static_cast<uint32_t>(rm_);
12065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        }
12165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      } else {
12265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        // Simple register
12365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        return static_cast<uint32_t>(rm_);
12465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      }
12565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    default:
12665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      // Can't get here.
12765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      LOG(FATAL) << "Invalid shifter operand for ARM";
12865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      return 0;
129a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro  }
130a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro}
131a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro
13245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allisonuint32_t ShifterOperand::encodingThumb() const {
13345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison  switch (type_) {
13445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    case kImmediate:
13545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      return immed_;
13645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    case kRegister:
13745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      if (is_shift_) {
13845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison        // Shifted immediate or register.
13945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison        if (rs_ == kNoRegister) {
14045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison          // Immediate shift.
14145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison          if (shift_ == RRX) {
14273cf0fb75de2a449ce4fe329b5f1fb42eef1372fVladimir Marko            DCHECK_EQ(immed_, 0u);
14345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison            // RRX is encoded as an ROR with imm 0.
14445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison            return ROR << 4 | static_cast<uint32_t>(rm_);
14565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          } else {
14673cf0fb75de2a449ce4fe329b5f1fb42eef1372fVladimir Marko            DCHECK((1 <= immed_ && immed_ <= 31) ||
14773cf0fb75de2a449ce4fe329b5f1fb42eef1372fVladimir Marko                   (immed_ == 0u && shift_ == LSL) ||
14873cf0fb75de2a449ce4fe329b5f1fb42eef1372fVladimir Marko                   (immed_ == 32u && (shift_ == ASR || shift_ == LSR)));
14973cf0fb75de2a449ce4fe329b5f1fb42eef1372fVladimir Marko            uint32_t imm3 = (immed_ >> 2) & 7 /* 0b111*/;
150c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe            uint32_t imm2 = immed_ & 3U /* 0b11 */;
15145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison
15245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison            return imm3 << 12 | imm2 << 6 | shift_ << 4 |
15345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison                static_cast<uint32_t>(rm_);
15465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison          }
15565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        } else {
15645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison          LOG(FATAL) << "No register-shifted register instruction available in thumb";
15745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison          return 0;
15865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        }
15945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      } else {
16045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison        // Simple register
16145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison        return static_cast<uint32_t>(rm_);
16245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      }
16345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    default:
16445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      // Can't get here.
16545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      LOG(FATAL) << "Invalid shifter operand for thumb";
16665b798ea10dd716c1bb3dda029f9bf255435af72Andreas Gampe      UNREACHABLE();
167a2e18e1e77fc25c8260aad5daa267ababfcb65f6Carl Shapiro  }
16865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison}
16965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
17065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t Address::encodingArm() const {
171ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe  CHECK(IsAbsoluteUint<12>(offset_));
17265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t encoding;
17345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison  if (is_immed_offset_) {
17445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (offset_ < 0) {
17545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding = (am_ ^ (1 << kUShift)) | -offset_;  // Flip U to adjust sign.
17645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    } else {
17745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding =  am_ | offset_;
17845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
179b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
18045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    uint32_t shift = shift_;
18145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (shift == RRX) {
1829f612ffab2b188d80027d961d7118eb2c461b5adAndreas Gampe      CHECK_EQ(offset_, 0);
18345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      shift = ROR;
18445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
18545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    encoding = am_ | static_cast<uint32_t>(rm_) | shift << 5 | offset_ << 7 | B25;
18665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  }
18765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  encoding |= static_cast<uint32_t>(rn_) << kRnShift;
18865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return encoding;
18965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison}
19065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
19165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
19245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allisonuint32_t Address::encodingThumb(bool is_32bit) const {
19365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t encoding = 0;
19445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison  if (is_immed_offset_) {
19545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    encoding = static_cast<uint32_t>(rn_) << 16;
19645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // Check for the T3/T4 encoding.
19745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // PUW must Offset for T3
19845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // Convert ARM PU0W to PUW
19945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // The Mode is in ARM encoding format which is:
20045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // |P|U|0|W|
20145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // we need this in thumb2 mode:
20245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // |P|U|W|
20345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison
20445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    uint32_t am = am_;
20545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    int32_t offset = offset_;
20645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (offset < 0) {
20745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      am ^= 1 << kUShift;
20845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      offset = -offset;
20945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
21045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (offset_ < 0 || (offset >= 0 && offset < 256 &&
21165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison        am_ != Mode::Offset)) {
21245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      // T4 encoding.
21345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      uint32_t PUW = am >> 21;   // Move down to bottom of word.
21445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      PUW = (PUW >> 1) | (PUW & 1);   // Bits 3, 2 and 0.
21545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      // If P is 0 then W must be 1 (Different from ARM).
216c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe      if ((PUW & 4U /* 0b100 */) == 0) {
217c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe        PUW |= 1U /* 0b1 */;
21865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      }
21945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding |= B11 | PUW << 8 | offset;
22045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    } else {
22145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      // T3 encoding (also sets op1 to 0b01).
22245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding |= B23 | offset_;
22345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
22465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  } else {
22545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // Register offset, possibly shifted.
22645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // Need to choose between encoding T1 (16 bit) or T2.
22745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // Only Offset mode is supported.  Shift must be LSL and the count
22845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    // is only 2 bits.
22945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    CHECK_EQ(shift_, LSL);
23045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    CHECK_LE(offset_, 4);
23145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    CHECK_EQ(am_, Offset);
23245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    bool is_t2 = is_32bit;
23345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (ArmAssembler::IsHighRegister(rn_) || ArmAssembler::IsHighRegister(rm_)) {
23445fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      is_t2 = true;
23545fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    } else if (offset_ != 0) {
23645fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      is_t2 = true;
23745fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
23845fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    if (is_t2) {
23945fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding = static_cast<uint32_t>(rn_) << 16 | static_cast<uint32_t>(rm_) |
24045fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison          offset_ << 4;
24145fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    } else {
24245fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison      encoding = static_cast<uint32_t>(rn_) << 3 | static_cast<uint32_t>(rm_) << 6;
24345fdb93f04b981f70f7b6d98949ab3986b7331f8Dave Allison    }
244b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
24565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return encoding;
246b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
247b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
24865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison// This is very like the ARM encoding except the offset is 10 bits.
24965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t Address::encodingThumbLdrdStrd() const {
2502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  DCHECK(IsImmediate());
25165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t encoding;
25265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t am = am_;
25365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // If P is 0 then W must be 1 (Different from ARM).
25465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t PU1W = am_ >> 21;   // Move down to bottom of word.
255c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe  if ((PU1W & 8U /* 0b1000 */) == 0) {
25665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    am |= 1 << 21;      // Set W bit.
25765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  }
25865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (offset_ < 0) {
25965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    int32_t off = -offset_;
26065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    CHECK_LT(off, 1024);
26114d90579f013b374638b599361970557ed4b3f09Roland Levillain    CHECK_ALIGNED(off, 4);
26265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    encoding = (am ^ (1 << kUShift)) | off >> 2;  // Flip U to adjust sign.
263b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
26465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    CHECK_LT(offset_, 1024);
26514d90579f013b374638b599361970557ed4b3f09Roland Levillain    CHECK_ALIGNED(offset_, 4);
26665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    encoding =  am | offset_ >> 2;
267b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
26865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  encoding |= static_cast<uint32_t>(rn_) << 16;
26965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return encoding;
270b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
271b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
27265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison// Encoding for ARM addressing mode 3.
27365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t Address::encoding3() const {
27465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  const uint32_t offset_mask = (1 << 12) - 1;
27565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t encoding = encodingArm();
27665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t offset = encoding & offset_mask;
27765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  CHECK_LT(offset, 256u);
27865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return (encoding & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf);
27965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison}
280b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
28165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison// Encoding for vfp load/store addressing.
28265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t Address::vencoding() const {
283ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe  CHECK(IsAbsoluteUint<10>(offset_));  // In the range -1020 to +1020.
284ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe  CHECK_ALIGNED(offset_, 2);  // Multiple of 4.
285ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe
28665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  const uint32_t offset_mask = (1 << 12) - 1;
28765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t encoding = encodingArm();
28865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t offset = encoding & offset_mask;
28965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  CHECK((am_ == Offset) || (am_ == NegOffset));
290277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe  uint32_t vencoding_value = (encoding & (0xf << kRnShift)) | (offset >> 2);
29165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (am_ == Offset) {
292277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe    vencoding_value |= 1 << 23;
293b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
294277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe  return vencoding_value;
295b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
296b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
297b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
29865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonbool Address::CanHoldLoadOffsetArm(LoadOperandType type, int offset) {
299b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  switch (type) {
300b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadSignedByte:
301b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadSignedHalfword:
302b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadUnsignedHalfword:
303b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadWordPair:
304ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<8>(offset);  // Addressing mode 3.
305b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadUnsignedByte:
306b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadWord:
307ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<12>(offset);  // Addressing mode 2.
308b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadSWord:
309b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadDWord:
310ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<10>(offset);  // VFP addressing mode.
311b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    default:
312b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      LOG(FATAL) << "UNREACHABLE";
3132c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers      UNREACHABLE();
314b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
315b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
316b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
317b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
31865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonbool Address::CanHoldStoreOffsetArm(StoreOperandType type, int offset) {
319b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  switch (type) {
320b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreHalfword:
321b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreWordPair:
322ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<8>(offset);  // Addressing mode 3.
323b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreByte:
324b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreWord:
325ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<12>(offset);  // Addressing mode 2.
326b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreSWord:
327b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreDWord:
328ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<10>(offset);  // VFP addressing mode.
329b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    default:
330b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      LOG(FATAL) << "UNREACHABLE";
3312c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers      UNREACHABLE();
332b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
333b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
334b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
33565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonbool Address::CanHoldLoadOffsetThumb(LoadOperandType type, int offset) {
336b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  switch (type) {
337b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadSignedByte:
338b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadSignedHalfword:
339b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadUnsignedHalfword:
34065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kLoadUnsignedByte:
341b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadWord:
342ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<12>(offset);
34365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kLoadSWord:
34465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kLoadDWord:
3456fd0ffe8da212723a3ac0256ce350b5872cc61d4Vladimir Marko      return IsAbsoluteUint<10>(offset) && (offset & 3) == 0;  // VFP addressing mode.
346b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kLoadWordPair:
3476fd0ffe8da212723a3ac0256ce350b5872cc61d4Vladimir Marko      return IsAbsoluteUint<10>(offset) && (offset & 3) == 0;
3482c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers    default:
349b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      LOG(FATAL) << "UNREACHABLE";
3502c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers      UNREACHABLE();
351b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
352b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
353b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
354b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
35565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonbool Address::CanHoldStoreOffsetThumb(StoreOperandType type, int offset) {
356b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  switch (type) {
357b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreHalfword:
35865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kStoreByte:
359b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreWord:
360ab1eb0d1d047e3478ebb891e5259d2f1d1dd78bdAndreas Gampe      return IsAbsoluteUint<12>(offset);
36165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kStoreSWord:
36265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    case kStoreDWord:
3636fd0ffe8da212723a3ac0256ce350b5872cc61d4Vladimir Marko      return IsAbsoluteUint<10>(offset) && (offset & 3) == 0;  // VFP addressing mode.
364b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    case kStoreWordPair:
3656fd0ffe8da212723a3ac0256ce350b5872cc61d4Vladimir Marko      return IsAbsoluteUint<10>(offset) && (offset & 3) == 0;
3662c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers    default:
367b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      LOG(FATAL) << "UNREACHABLE";
3682c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers      UNREACHABLE();
369b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
370b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
371b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
37265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonvoid ArmAssembler::Pad(uint32_t bytes) {
37365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
37465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  for (uint32_t i = 0; i < bytes; ++i) {
37513735955f39b3b304c37d2b2840663c131262c18Ian Rogers    buffer_.Emit<uint8_t>(0);
3769b9ba28b1277b4ddb967c5a968c6d550febce6afCarl Shapiro  }
3779b9ba28b1277b4ddb967c5a968c6d550febce6afCarl Shapiro}
3789b9ba28b1277b4ddb967c5a968c6d550febce6afCarl Shapiro
379dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbeckystatic dwarf::Reg DWARFReg(Register reg) {
380dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  return dwarf::Reg::ArmCore(static_cast<int>(reg));
381dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky}
382dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
383dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbeckystatic dwarf::Reg DWARFReg(SRegister reg) {
384dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  return dwarf::Reg::ArmFp(static_cast<int>(reg));
385dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky}
386dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
387e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartierconstexpr size_t kFramePointerSize = kArmPointerSize;
388790a6b7312979513710c366b411ba6791ddf78c2Ian Rogers
3892c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
390b5d09b2f87202bc132ac3991d4b6d71f4f6d9264Ian Rogers                              const std::vector<ManagedRegister>& callee_save_regs,
391fca82208f7128fcda09b6a4743199308332558a2Dmitry Petrochenko                              const ManagedRegisterEntrySpills& entry_spills) {
392dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  CHECK_EQ(buffer_.Size(), 0U);  // Nothing emitted yet
39306b37d91bb3d543002b1aee9829691f5e8bebc7eElliott Hughes  CHECK_ALIGNED(frame_size, kStackAlignment);
3942c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  CHECK_EQ(R0, method_reg.AsArm().AsCoreRegister());
395bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
39600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // Push callee saves and link register.
397dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  RegList core_spill_mask = 1 << LR;
398dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  uint32_t fp_spill_mask = 0;
399dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  for (const ManagedRegister& reg : callee_save_regs) {
400dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    if (reg.AsArm().IsCoreRegister()) {
401dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky      core_spill_mask |= 1 << reg.AsArm().AsCoreRegister();
4027cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz    } else {
403dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky      fp_spill_mask |= 1 << reg.AsArm().AsSRegister();
4047cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz    }
4050d666d8769714dcbc2acc4dd5b06f0deffa6e0a1Ian Rogers  }
406dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  PushList(core_spill_mask);
407dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize);
408dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.RelOffsetForMany(DWARFReg(Register(0)), 0, core_spill_mask, kFramePointerSize);
409dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  if (fp_spill_mask != 0) {
410dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    vpushs(SRegister(CTZ(fp_spill_mask)), POPCOUNT(fp_spill_mask));
411dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    cfi_.AdjustCFAOffset(POPCOUNT(fp_spill_mask) * kFramePointerSize);
412dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    cfi_.RelOffsetForMany(DWARFReg(SRegister(0)), 0, fp_spill_mask, kFramePointerSize);
4137cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
414bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
41500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // Increase frame to required size.
416dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  int pushed_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask);
417790a6b7312979513710c366b411ba6791ddf78c2Ian Rogers  CHECK_GT(frame_size, pushed_values * kFramePointerSize);  // Must at least have space for Method*.
418dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  IncreaseFrameSize(frame_size - pushed_values * kFramePointerSize);  // handles CFI as well.
419bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
42000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // Write out Method*.
421bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  StoreToOffset(kStoreWord, R0, SP, 0);
42200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
42300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // Write out entry spills.
424e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  int32_t offset = frame_size + kFramePointerSize;
42500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  for (size_t i = 0; i < entry_spills.size(); ++i) {
4265667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    ArmManagedRegister reg = entry_spills.at(i).AsArm();
4275667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    if (reg.IsNoRegister()) {
4285667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      // only increment stack offset.
4295667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      ManagedRegisterSpill spill = entry_spills.at(i);
4305667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      offset += spill.getSize();
4315667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    } else if (reg.IsCoreRegister()) {
4325667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
4335667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      offset += 4;
4345667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    } else if (reg.IsSRegister()) {
4355667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      StoreSToOffset(reg.AsSRegister(), SP, offset);
4365667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      offset += 4;
4375667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    } else if (reg.IsDRegister()) {
4385667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      StoreDToOffset(reg.AsDRegister(), SP, offset);
4395667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu      offset += 8;
4405667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu    }
44100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
442b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
443b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4442c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::RemoveFrame(size_t frame_size,
445bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers                              const std::vector<ManagedRegister>& callee_save_regs) {
44606b37d91bb3d543002b1aee9829691f5e8bebc7eElliott Hughes  CHECK_ALIGNED(frame_size, kStackAlignment);
447dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.RememberState();
448dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
44965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Compute callee saves to pop and PC.
450dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  RegList core_spill_mask = 1 << PC;
451dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  uint32_t fp_spill_mask = 0;
452dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  for (const ManagedRegister& reg : callee_save_regs) {
453dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    if (reg.AsArm().IsCoreRegister()) {
454dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky      core_spill_mask |= 1 << reg.AsArm().AsCoreRegister();
4557cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz    } else {
456dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky      fp_spill_mask |= 1 << reg.AsArm().AsSRegister();
4577cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz    }
4587cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
4597cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
46065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Decrease frame to start of callee saves.
461dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  int pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask);
462790a6b7312979513710c366b411ba6791ddf78c2Ian Rogers  CHECK_GT(frame_size, pop_values * kFramePointerSize);
463dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  DecreaseFrameSize(frame_size - (pop_values * kFramePointerSize));  // handles CFI as well.
464bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
465dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  if (fp_spill_mask != 0) {
466dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    vpops(SRegister(CTZ(fp_spill_mask)), POPCOUNT(fp_spill_mask));
467dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    cfi_.AdjustCFAOffset(-kFramePointerSize * POPCOUNT(fp_spill_mask));
468dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky    cfi_.RestoreMany(DWARFReg(SRegister(0)), fp_spill_mask);
4697cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
4707cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
47165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Pop callee saves and PC.
472dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  PopList(core_spill_mask);
473dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
474dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  // The CFI should be restored for any code that follows the exit block.
475dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.RestoreState();
476dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.DefCFAOffset(frame_size);
4770d666d8769714dcbc2acc4dd5b06f0deffa6e0a1Ian Rogers}
4780d666d8769714dcbc2acc4dd5b06f0deffa6e0a1Ian Rogers
4792c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::IncreaseFrameSize(size_t adjust) {
480b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  AddConstant(SP, -adjust);
481dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.AdjustCFAOffset(adjust);
482b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
483b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4842c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::DecreaseFrameSize(size_t adjust) {
485b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  AddConstant(SP, adjust);
486dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.AdjustCFAOffset(-adjust);
487b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
488b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4892c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
4902c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister src = msrc.AsArm();
491e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  if (src.IsNoRegister()) {
492e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    CHECK_EQ(0u, size);
493e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  } else if (src.IsCoreRegister()) {
494b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    CHECK_EQ(4u, size);
495b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
496e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  } else if (src.IsRegisterPair()) {
497e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    CHECK_EQ(8u, size);
498e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
499e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
500e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro                  SP, dest.Int32Value() + 4);
501e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  } else if (src.IsSRegister()) {
502e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    StoreSToOffset(src.AsSRegister(), SP, dest.Int32Value());
503b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
504bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    CHECK(src.IsDRegister()) << src;
505e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value());
506b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
507b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
508b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
5092c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
5102c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister src = msrc.AsArm();
511bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(src.IsCoreRegister()) << src;
512b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
513b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
514b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
5152c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
5162c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister src = msrc.AsArm();
517bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(src.IsCoreRegister()) << src;
518df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
519df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers}
520df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers
5212c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
5222c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                              FrameOffset in_off, ManagedRegister mscratch) {
5232c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister src = msrc.AsArm();
5242c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
5257a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers  StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
5267a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
5277a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
5287a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers}
5297a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers
5302c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::CopyRef(FrameOffset dest, FrameOffset src,
5312c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                        ManagedRegister mscratch) {
5322c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
533b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
534b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
535b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
536b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
537e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartiervoid ArmAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
5384d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain                           bool unpoison_reference) {
539bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = mdest.AsArm();
540bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
541bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
5422c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                 base.AsArm().AsCoreRegister(), offs.Int32Value());
5434d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  if (unpoison_reference) {
5444d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    MaybeUnpoisonHeapReference(dst.AsCoreRegister());
545e63a745f26fec5a5b4162fc83f6e88a1f696c30cHiroshi Yamauchi  }
546b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
547b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
5482c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::LoadRef(ManagedRegister mdest, FrameOffset  src) {
549bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = mdest.AsArm();
550bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(dst.IsCoreRegister()) << dst;
551bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  LoadFromOffset(kLoadWord, dst.AsCoreRegister(), SP, src.Int32Value());
552362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes}
5532c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
5542c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
555a04d397b990ee7d3ce120e317c19fb4409d80d57Ian Rogers                           Offset offs) {
556bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = mdest.AsArm();
557bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
558bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
5592c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                 base.AsArm().AsCoreRegister(), offs.Int32Value());
560a04d397b990ee7d3ce120e317c19fb4409d80d57Ian Rogers}
561a04d397b990ee7d3ce120e317c19fb4409d80d57Ian Rogers
5622c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
5632c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                      ManagedRegister mscratch) {
5642c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
565bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
566b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadImmediate(scratch.AsCoreRegister(), imm);
567b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
568b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
569b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
570dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm,
5712c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                       ManagedRegister mscratch) {
5722c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
573bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
574b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadImmediate(scratch.AsCoreRegister(), imm);
575b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), TR, dest.Int32Value());
576b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
577b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
578bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughesstatic void EmitLoad(ArmAssembler* assembler, ManagedRegister m_dst,
579bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes                     Register src_register, int32_t src_offset, size_t size) {
580bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = m_dst.AsArm();
581bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  if (dst.IsNoRegister()) {
582bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    CHECK_EQ(0u, size) << dst;
583bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  } else if (dst.IsCoreRegister()) {
584bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    CHECK_EQ(4u, size) << dst;
585bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    assembler->LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
586bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  } else if (dst.IsRegisterPair()) {
587bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    CHECK_EQ(8u, size) << dst;
588bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    assembler->LoadFromOffset(kLoadWord, dst.AsRegisterPairLow(), src_register, src_offset);
589bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    assembler->LoadFromOffset(kLoadWord, dst.AsRegisterPairHigh(), src_register, src_offset + 4);
590bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  } else if (dst.IsSRegister()) {
591bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    assembler->LoadSFromOffset(dst.AsSRegister(), src_register, src_offset);
592b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
593bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    CHECK(dst.IsDRegister()) << dst;
594bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    assembler->LoadDFromOffset(dst.AsDRegister(), src_register, src_offset);
595b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
596b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
597b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
598bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughesvoid ArmAssembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
599bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  return EmitLoad(this, m_dst, SP, src.Int32Value(), size);
6005a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers}
6015a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers
602dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::LoadFromThread32(ManagedRegister m_dst, ThreadOffset<4> src, size_t size) {
603bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  return EmitLoad(this, m_dst, TR, src.Int32Value(), size);
604bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes}
605bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes
606dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::LoadRawPtrFromThread32(ManagedRegister m_dst, ThreadOffset<4> offs) {
607bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = m_dst.AsArm();
608bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(dst.IsCoreRegister()) << dst;
609bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  LoadFromOffset(kLoadWord, dst.AsCoreRegister(), TR, offs.Int32Value());
610b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
611b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
612dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
613dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                        ThreadOffset<4> thr_offs,
6142c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                        ManagedRegister mscratch) {
6152c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
616bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
617b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
618b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                 TR, thr_offs.Int32Value());
619b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
620b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                SP, fr_offs.Int32Value());
621b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
622b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
623dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs,
6242c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                      FrameOffset fr_offs,
6252c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                      ManagedRegister mscratch) {
6262c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
627bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
628b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
629b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                 SP, fr_offs.Int32Value());
630b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
631b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                TR, thr_offs.Int32Value());
632b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
633b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
634dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,
6352c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                            FrameOffset fr_offs,
6362c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                            ManagedRegister mscratch) {
6372c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
638bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
639b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value(), AL);
640b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
641b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                TR, thr_offs.Int32Value());
642b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
643b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
644dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs) {
64545a76cb99104a222d6a9bd768a084893dcb7cf30Ian Rogers  StoreToOffset(kStoreWord, SP, TR, thr_offs.Int32Value());
64645a76cb99104a222d6a9bd768a084893dcb7cf30Ian Rogers}
64745a76cb99104a222d6a9bd768a084893dcb7cf30Ian Rogers
64858136caeec7cb677bb83c2eafd1f4bab5afd96c8jeffhaovoid ArmAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
64958136caeec7cb677bb83c2eafd1f4bab5afd96c8jeffhao  UNIMPLEMENTED(FATAL) << "no sign extension necessary for arm";
65058136caeec7cb677bb83c2eafd1f4bab5afd96c8jeffhao}
65158136caeec7cb677bb83c2eafd1f4bab5afd96c8jeffhao
652cee4d0c1c2faacf0eae748a24cc7e455e067d977jeffhaovoid ArmAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
653cee4d0c1c2faacf0eae748a24cc7e455e067d977jeffhao  UNIMPLEMENTED(FATAL) << "no zero extension necessary for arm";
654cee4d0c1c2faacf0eae748a24cc7e455e067d977jeffhao}
655cee4d0c1c2faacf0eae748a24cc7e455e067d977jeffhao
656bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughesvoid ArmAssembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t /*size*/) {
657bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister dst = m_dst.AsArm();
658bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  ArmManagedRegister src = m_src.AsArm();
659bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  if (!dst.Equals(src)) {
660bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    if (dst.IsCoreRegister()) {
661bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      CHECK(src.IsCoreRegister()) << src;
662bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      mov(dst.AsCoreRegister(), ShifterOperand(src.AsCoreRegister()));
663bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    } else if (dst.IsDRegister()) {
664bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      CHECK(src.IsDRegister()) << src;
665bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      vmovd(dst.AsDRegister(), src.AsDRegister());
666bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes    } else if (dst.IsSRegister()) {
667bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      CHECK(src.IsSRegister()) << src;
668bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      vmovs(dst.AsSRegister(), src.AsSRegister());
669e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    } else {
670bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      CHECK(dst.IsRegisterPair()) << dst;
671bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      CHECK(src.IsRegisterPair()) << src;
67265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      // Ensure that the first move doesn't clobber the input of the second.
673bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes      if (src.AsRegisterPairHigh() != dst.AsRegisterPairLow()) {
674bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes        mov(dst.AsRegisterPairLow(), ShifterOperand(src.AsRegisterPairLow()));
675bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes        mov(dst.AsRegisterPairHigh(), ShifterOperand(src.AsRegisterPairHigh()));
6767a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers      } else {
677bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes        mov(dst.AsRegisterPairHigh(), ShifterOperand(src.AsRegisterPairHigh()));
678bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes        mov(dst.AsRegisterPairLow(), ShifterOperand(src.AsRegisterPairLow()));
6797a99c11d220ec68c208b507570e3a78c2c18a7a1Ian Rogers      }
680e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    }
681b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
682b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
683b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
684dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogersvoid ArmAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
6852c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
686bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
687bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(size == 4 || size == 8) << size;
688b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  if (size == 4) {
689dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
690dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
6915381cf941d26030199fcdbe61a614ff01e55a27cShih-wei Liao  } else if (size == 8) {
692dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
693dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
694dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + 4);
695dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers    StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
696b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
697b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
698b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
699dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogersvoid ArmAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
700dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers                        ManagedRegister mscratch, size_t size) {
701dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  Register scratch = mscratch.AsArm().AsCoreRegister();
702dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  CHECK_EQ(size, 4u);
703dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  LoadFromOffset(kLoadWord, scratch, src_base.AsArm().AsCoreRegister(), src_offset.Int32Value());
704dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
705dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers}
706dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers
7075a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogersvoid ArmAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
7085a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers                        ManagedRegister mscratch, size_t size) {
7095a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  Register scratch = mscratch.AsArm().AsCoreRegister();
7105a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  CHECK_EQ(size, 4u);
7115a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
7125a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  StoreToOffset(kStoreWord, scratch, dest_base.AsArm().AsCoreRegister(), dest_offset.Int32Value());
7135a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers}
7145a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers
7151bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughesvoid ArmAssembler::Copy(FrameOffset /*dst*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
7161bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughes                        ManagedRegister /*mscratch*/, size_t /*size*/) {
717dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  UNIMPLEMENTED(FATAL);
718dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers}
719dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers
7205a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogersvoid ArmAssembler::Copy(ManagedRegister dest, Offset dest_offset,
7215a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers                        ManagedRegister src, Offset src_offset,
7225a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers                        ManagedRegister mscratch, size_t size) {
723dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  CHECK_EQ(size, 4u);
7245a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  Register scratch = mscratch.AsArm().AsCoreRegister();
7255a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  LoadFromOffset(kLoadWord, scratch, src.AsArm().AsCoreRegister(), src_offset.Int32Value());
7265a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  StoreToOffset(kStoreWord, scratch, dest.AsArm().AsCoreRegister(), dest_offset.Int32Value());
7275a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers}
7285a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers
7291bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughesvoid ArmAssembler::Copy(FrameOffset /*dst*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/,
7301bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughes                        ManagedRegister /*scratch*/, size_t /*size*/) {
7315a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  UNIMPLEMENTED(FATAL);
732dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers}
733dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers
734eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartiervoid ArmAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
735eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                                   FrameOffset handle_scope_offset,
7362c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                   ManagedRegister min_reg, bool null_allowed) {
7372c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister out_reg = mout_reg.AsArm();
7382c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister in_reg = min_reg.AsArm();
739bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
740bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(out_reg.IsCoreRegister()) << out_reg;
741b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  if (null_allowed) {
742eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
743eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // the address in the handle scope holding the reference.
744b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
745e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    if (in_reg.IsNoRegister()) {
746e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro      LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
747eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                     SP, handle_scope_offset.Int32Value());
748e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro      in_reg = out_reg;
749e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    }
750b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    cmp(in_reg.AsCoreRegister(), ShifterOperand(0));
751b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    if (!out_reg.Equals(in_reg)) {
75265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      it(EQ, kItElse);
753b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);
75465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    } else {
75565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      it(NE);
756b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    }
757eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
758b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
759eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
760b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
761b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
762b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
763eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartiervoid ArmAssembler::CreateHandleScopeEntry(FrameOffset out_off,
764eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                                   FrameOffset handle_scope_offset,
7652c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                   ManagedRegister mscratch,
7662c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                   bool null_allowed) {
7672c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
768bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
769b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  if (null_allowed) {
770b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
771eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                   handle_scope_offset.Int32Value());
772eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
773eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // the address in the handle scope holding the reference.
774eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
775b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    cmp(scratch.AsCoreRegister(), ShifterOperand(0));
77665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    it(NE);
777eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
778b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
779eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
780b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
781b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
782b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
783b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
784eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartiervoid ArmAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
7852c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                                         ManagedRegister min_reg) {
7862c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister out_reg = mout_reg.AsArm();
7872c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister in_reg = min_reg.AsArm();
788bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(out_reg.IsCoreRegister()) << out_reg;
789bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(in_reg.IsCoreRegister()) << in_reg;
790b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  Label null_arg;
791b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  if (!out_reg.Equals(in_reg)) {
79265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);     // TODO: why EQ?
793b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
794b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  cmp(in_reg.AsCoreRegister(), ShifterOperand(0));
79565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  it(NE);
796df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers  LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
797df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers                 in_reg.AsCoreRegister(), 0, NE);
798b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
799b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
8001bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughesvoid ArmAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
80165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // TODO: not validating references.
802b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
803b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
8041bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughesvoid ArmAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
80565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // TODO: not validating references.
806b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
807b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
8082c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::Call(ManagedRegister mbase, Offset offset,
8092c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                        ManagedRegister mscratch) {
8102c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister base = mbase.AsArm();
8112c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
812bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(base.IsCoreRegister()) << base;
813bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
814b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
815b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers                 base.AsCoreRegister(), offset.Int32Value());
816b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  blx(scratch.AsCoreRegister());
81765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // TODO: place reference map on call.
818b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
819b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
8202c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::Call(FrameOffset base, Offset offset,
8212c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                        ManagedRegister mscratch) {
8222c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
823bf2739d3b58ee5b2f190007499f1fbfd0b3441ceElliott Hughes  CHECK(scratch.IsCoreRegister()) << scratch;
824e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  // Call *(*(SP + base) + offset)
825e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
826e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro                 SP, base.Int32Value());
827e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
828e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro                 scratch.AsCoreRegister(), offset.Int32Value());
829e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  blx(scratch.AsCoreRegister());
830e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  // TODO: place reference map on call
831e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro}
832e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro
833dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersvoid ArmAssembler::CallFromThread32(ThreadOffset<4> /*offset*/, ManagedRegister /*scratch*/) {
834bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  UNIMPLEMENTED(FATAL);
835bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers}
836bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
8372c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::GetCurrentThread(ManagedRegister tr) {
8382c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  mov(tr.AsArm().AsCoreRegister(), ShifterOperand(TR));
839668512afd0d9b3772a0abc589208b729ee16bc61Shih-wei Liao}
840668512afd0d9b3772a0abc589208b729ee16bc61Shih-wei Liao
8412c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmAssembler::GetCurrentThread(FrameOffset offset,
8421bac54ffa933fbe9b92b62437577f2f4583eff1aElliott Hughes                                    ManagedRegister /*scratch*/) {
843668512afd0d9b3772a0abc589208b729ee16bc61Shih-wei Liao  StoreToOffset(kStoreWord, TR, SP, offset.Int32Value(), AL);
844668512afd0d9b3772a0abc589208b729ee16bc61Shih-wei Liao}
845668512afd0d9b3772a0abc589208b729ee16bc61Shih-wei Liao
84600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogersvoid ArmAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
8472c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmManagedRegister scratch = mscratch.AsArm();
848d1ee80948144526b985afb44a0574248cf7da58aVladimir Marko  ArmExceptionSlowPath* slow = new (GetArena()) ArmExceptionSlowPath(scratch, stack_adjust);
849e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  buffer_.EnqueueSlowPath(slow);
850e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
851dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                 TR, Thread::ExceptionOffset<4>().Int32Value());
852e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  cmp(scratch.AsCoreRegister(), ShifterOperand(0));
853e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  b(slow->Entry(), NE);
854e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro}
855e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro
8562c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogersvoid ArmExceptionSlowPath::Emit(Assembler* sasm) {
8572c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  ArmAssembler* sp_asm = down_cast<ArmAssembler*>(sasm);
8582c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#define __ sp_asm->
8592c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  __ Bind(&entry_);
86000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (stack_adjust_ != 0) {  // Fix up the frame.
86100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    __ DecreaseFrameSize(stack_adjust_);
86200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
86365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Pass exception object as argument.
86465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Don't care about preserving R0 as this call won't return.
86567375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers  __ mov(R0, ShifterOperand(scratch_.AsCoreRegister()));
86665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  // Set up call to Thread::Current()->pDeliverException.
867dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers  __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
8682c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  __ blx(R12);
8692c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#undef __
87045a76cb99104a222d6a9bd768a084893dcb7cf30Ian Rogers}
87145a76cb99104a222d6a9bd768a084893dcb7cf30Ian Rogers
87265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
87365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonstatic int LeadingZeros(uint32_t val) {
87465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t alt;
87565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  int32_t n;
87665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  int32_t count;
87765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
87865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  count = 16;
87965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  n = 32;
88065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  do {
88165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    alt = val >> count;
88265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    if (alt != 0) {
88365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      n = n - count;
88465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison      val = alt;
88565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    }
88665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    count >>= 1;
88765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  } while (count);
88865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return n - val;
88965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison}
89065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
89165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
89265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allisonuint32_t ArmAssembler::ModifiedImmediate(uint32_t value) {
89365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  int32_t z_leading;
89465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  int32_t z_trailing;
89565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t b0 = value & 0xff;
89665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
89765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* Note: case of value==0 must use 0:000:0:0000000 encoding */
89865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (value <= 0xFF)
89965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    return b0;  // 0:000:a:bcdefgh.
90065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (value == ((b0 << 16) | b0))
90165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    return (0x1 << 12) | b0; /* 0:001:a:bcdefgh */
90265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
90365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    return (0x3 << 12) | b0; /* 0:011:a:bcdefgh */
90465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  b0 = (value >> 8) & 0xff;
90565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if (value == ((b0 << 24) | (b0 << 8)))
90665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    return (0x2 << 12) | b0; /* 0:010:a:bcdefgh */
90765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* Can we do it with rotation? */
90865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  z_leading = LeadingZeros(value);
90965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  z_trailing = 32 - LeadingZeros(~value & (value - 1));
91065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* A run of eight or fewer active bits? */
91165fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  if ((z_leading + z_trailing) < 24)
91265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison    return kInvalidModifiedImmediate;  /* No - bail */
91365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* left-justify the constant, discarding msb (known to be 1) */
91465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  value <<= z_leading + 1;
91565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* Create bcdefgh */
91665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  value >>= 25;
91765fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
91865fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  /* Put it all together */
91965fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t v = 8 + z_leading;
92065fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
921c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe  uint32_t i = (v & 16U /* 0b10000 */) >> 4;
922c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe  uint32_t imm3 = (v >> 1) & 7U /* 0b111 */;
92365fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  uint32_t a = v & 1;
92465fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison  return value | i << 26 | imm3 << 12 | a << 7;
92565fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison}
92665fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison
9277cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampevoid ArmAssembler::FinalizeTrackedLabels() {
9287cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe  if (!tracked_labels_.empty()) {
9297cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    // This array should be sorted, as assembly is generated in linearized order. It isn't
9307cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    // technically required, but GetAdjustedPosition() used in AdjustLabelPosition() can take
9317cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    // advantage of it. So ensure that it's actually the case.
9327cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    DCHECK(std::is_sorted(
9337cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe        tracked_labels_.begin(),
9347cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe        tracked_labels_.end(),
9357cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe        [](const Label* lhs, const Label* rhs) { return lhs->Position() < rhs->Position(); }));
9367cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe
9377cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    Label* last_label = nullptr;  // Track duplicates, we must not adjust twice.
9387cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    for (Label* label : tracked_labels_) {
9397cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe      DCHECK_NE(label, last_label);
9407cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe      AdjustLabelPosition(label);
9417cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe      last_label = label;
9427cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe    }
9437cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe  }
9447cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe}
9457cffc3b0004d32faffc552c0a59286f369b21504Andreas Gampe
9462c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers}  // namespace arm
9476b6b5f0e67ce03f38223a525612955663bc1799bCarl Shapiro}  // namespace art
948