1ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu/*
2ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * Copyright (C) 2014 The Android Open Source Project
3ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu *
4ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * Licensed under the Apache License, Version 2.0 (the "License");
5ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * you may not use this file except in compliance with the License.
6ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * You may obtain a copy of the License at
7ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu *
8ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu *      http://www.apache.org/licenses/LICENSE-2.0
9ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu *
10ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * Unless required by applicable law or agreed to in writing, software
11ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * distributed under the License is distributed on an "AS IS" BASIS,
12ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * See the License for the specific language governing permissions and
14ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu * limitations under the License.
15ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu */
16ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
17ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#include "assembler_arm64.h"
18ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#include "base/logging.h"
19ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#include "entrypoints/quick/quick_entrypoints.h"
20ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#include "offsets.h"
21ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#include "thread.h"
22ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
23ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Ramesusing namespace vixl;  // NOLINT(build/namespaces)
24ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames
25ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescunamespace art {
26ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescunamespace arm64 {
27ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
28ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#ifdef ___
29ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#error "ARM64 Assembler macro already defined."
30ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#else
31ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#define ___   vixl_masm_->
32ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu#endif
33ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
34cf93a5cd9c978f59113d42f9f642fab5e2cc8877Vladimir Markovoid Arm64Assembler::FinalizeCode() {
35c393d63aa2b8f6984672fdd4de631bbeff14b6a2Alexandre Rames  for (const std::unique_ptr<Arm64Exception>& exception : exception_blocks_) {
36c393d63aa2b8f6984672fdd4de631bbeff14b6a2Alexandre Rames    EmitExceptionPoll(exception.get());
37ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
38ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ FinalizeCode();
39ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
40ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
41ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescusize_t Arm64Assembler::CodeSize() const {
42cee7524afa53216fcd13df8122ece495548a829cAlexandre Rames  return vixl_masm_->BufferCapacity() - vixl_masm_->RemainingBufferSpace();
43ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
44ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
45eb7b7399dbdb5e471b8ae00a567bf4f19edd3907Alexandre Ramesconst uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
46eb7b7399dbdb5e471b8ae00a567bf4f19edd3907Alexandre Rames  return vixl_masm_->GetStartAddress<uint8_t*>();
47eb7b7399dbdb5e471b8ae00a567bf4f19edd3907Alexandre Rames}
48eb7b7399dbdb5e471b8ae00a567bf4f19edd3907Alexandre Rames
49ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
50ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Copy the instructions from the buffer.
51cee7524afa53216fcd13df8122ece495548a829cAlexandre Rames  MemoryRegion from(vixl_masm_->GetStartAddress<void*>(), CodeSize());
52ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  region.CopyFrom(0, from);
53ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
54ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
55ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::GetCurrentThread(ManagedRegister tr) {
569bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  ___ Mov(reg_x(tr.AsArm64().AsXRegister()), reg_x(TR));
57ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
58ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
59ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) {
609bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  StoreToOffset(TR, SP, offset.Int32Value());
61ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
62ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
63ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// See Arm64 PCS Section 5.2.2.1.
64ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::IncreaseFrameSize(size_t adjust) {
65ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK_ALIGNED(adjust, kStackAlignment);
66ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  AddConstant(SP, -adjust);
67dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi().AdjustCFAOffset(adjust);
68ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
69ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
70ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// See Arm64 PCS Section 5.2.2.1.
71ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::DecreaseFrameSize(size_t adjust) {
72ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK_ALIGNED(adjust, kStackAlignment);
73ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  AddConstant(SP, adjust);
74dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi().AdjustCFAOffset(-adjust);
75ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
76ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
7737c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::AddConstant(XRegister rd, int32_t value, Condition cond) {
78ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  AddConstant(rd, rd, value, cond);
79ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
80ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
8137c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::AddConstant(XRegister rd, XRegister rn, int32_t value,
82ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                 Condition cond) {
83ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames  if ((cond == al) || (cond == nv)) {
84ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    // VIXL macro-assembler handles all variants.
85ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    ___ Add(reg_x(rd), reg_x(rn), value);
86ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
870f89dac7336251f7921621a926319d461837840fSerban Constantinescu    // temp = rd + value
880f89dac7336251f7921621a926319d461837840fSerban Constantinescu    // rd = cond ? temp : rn
890f89dac7336251f7921621a926319d461837840fSerban Constantinescu    vixl::UseScratchRegisterScope temps(vixl_masm_);
900f89dac7336251f7921621a926319d461837840fSerban Constantinescu    temps.Exclude(reg_x(rd), reg_x(rn));
910f89dac7336251f7921621a926319d461837840fSerban Constantinescu    vixl::Register temp = temps.AcquireX();
920f89dac7336251f7921621a926319d461837840fSerban Constantinescu    ___ Add(temp, reg_x(rn), value);
93ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames    ___ Csel(reg_x(rd), temp, reg_x(rd), cond);
94ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
95ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
96ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
97ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::StoreWToOffset(StoreOperandType type, WRegister source,
9837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames                                    XRegister base, int32_t offset) {
99ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  switch (type) {
100ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kStoreByte:
101ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Strb(reg_w(source), MEM_OP(reg_x(base), offset));
102ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
103ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kStoreHalfword:
104ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Strh(reg_w(source), MEM_OP(reg_x(base), offset));
105ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
106ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kStoreWord:
107ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Str(reg_w(source), MEM_OP(reg_x(base), offset));
108ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
109ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    default:
110ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      LOG(FATAL) << "UNREACHABLE";
111ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
112ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
113ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
11437c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::StoreToOffset(XRegister source, XRegister base, int32_t offset) {
115ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK_NE(source, SP);
116ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Str(reg_x(source), MEM_OP(reg_x(base), offset));
117ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
118ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
11937c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::StoreSToOffset(SRegister source, XRegister base, int32_t offset) {
120ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Str(reg_s(source), MEM_OP(reg_x(base), offset));
121ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
122ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
12337c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::StoreDToOffset(DRegister source, XRegister base, int32_t offset) {
124ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Str(reg_d(source), MEM_OP(reg_x(base), offset));
125ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
126ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
127ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Store(FrameOffset offs, ManagedRegister m_src, size_t size) {
128ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister src = m_src.AsArm64();
129ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (src.IsNoRegister()) {
130ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK_EQ(0u, size);
131ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (src.IsWRegister()) {
132ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK_EQ(4u, size);
133ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    StoreWToOffset(kStoreWord, src.AsWRegister(), SP, offs.Int32Value());
13437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  } else if (src.IsXRegister()) {
135ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK_EQ(8u, size);
13637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreToOffset(src.AsXRegister(), SP, offs.Int32Value());
137ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (src.IsSRegister()) {
138ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    StoreSToOffset(src.AsSRegister(), SP, offs.Int32Value());
139ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
140ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK(src.IsDRegister()) << src;
141ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    StoreDToOffset(src.AsDRegister(), SP, offs.Int32Value());
142ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
143ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
144ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
145ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::StoreRef(FrameOffset offs, ManagedRegister m_src) {
146ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister src = m_src.AsArm64();
14737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(src.IsXRegister()) << src;
14837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreWToOffset(kStoreWord, src.AsOverlappingWRegister(), SP,
14975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                 offs.Int32Value());
150ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
151ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
152ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::StoreRawPtr(FrameOffset offs, ManagedRegister m_src) {
153ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister src = m_src.AsArm64();
15437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(src.IsXRegister()) << src;
15537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreToOffset(src.AsXRegister(), SP, offs.Int32Value());
156ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
157ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
158ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::StoreImmediateToFrame(FrameOffset offs, uint32_t imm,
159ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                           ManagedRegister m_scratch) {
160ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
16137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
16237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadImmediate(scratch.AsXRegister(), imm);
16337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP,
16475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                 offs.Int32Value());
165ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
166ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
16775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::StoreImmediateToThread64(ThreadOffset<8> offs, uint32_t imm,
168ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                            ManagedRegister m_scratch) {
169ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
17037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
17137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadImmediate(scratch.AsXRegister(), imm);
1729bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  StoreToOffset(scratch.AsXRegister(), TR, offs.Int32Value());
173ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
174ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
17575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> tr_offs,
176ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                              FrameOffset fr_offs,
177ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                              ManagedRegister m_scratch) {
178ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
17937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
18037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  AddConstant(scratch.AsXRegister(), SP, fr_offs.Int32Value());
1819bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
182ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
183ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
18475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::StoreStackPointerToThread64(ThreadOffset<8> tr_offs) {
1850f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::UseScratchRegisterScope temps(vixl_masm_);
1860f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::Register temp = temps.AcquireX();
1870f89dac7336251f7921621a926319d461837840fSerban Constantinescu  ___ Mov(temp, reg_x(SP));
1889bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  ___ Str(temp, MEM_OP(reg_x(TR), tr_offs.Int32Value()));
189ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
190ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
191ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::StoreSpanning(FrameOffset dest_off, ManagedRegister m_source,
192ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                   FrameOffset in_off, ManagedRegister m_scratch) {
193ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister source = m_source.AsArm64();
194ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
19537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreToOffset(source.AsXRegister(), SP, dest_off.Int32Value());
19637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadFromOffset(scratch.AsXRegister(), SP, in_off.Int32Value());
19737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreToOffset(scratch.AsXRegister(), SP, dest_off.Int32Value() + 8);
198ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
199ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
200ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// Load routines.
20137c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::LoadImmediate(XRegister dest, int32_t value,
202ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                   Condition cond) {
203ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames  if ((cond == al) || (cond == nv)) {
204ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    ___ Mov(reg_x(dest), value);
205ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
2060f89dac7336251f7921621a926319d461837840fSerban Constantinescu    // temp = value
2070f89dac7336251f7921621a926319d461837840fSerban Constantinescu    // rd = cond ? temp : rd
208ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    if (value != 0) {
2090f89dac7336251f7921621a926319d461837840fSerban Constantinescu      vixl::UseScratchRegisterScope temps(vixl_masm_);
2100f89dac7336251f7921621a926319d461837840fSerban Constantinescu      temps.Exclude(reg_x(dest));
2110f89dac7336251f7921621a926319d461837840fSerban Constantinescu      vixl::Register temp = temps.AcquireX();
2120f89dac7336251f7921621a926319d461837840fSerban Constantinescu      ___ Mov(temp, value);
213ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames      ___ Csel(reg_x(dest), temp, reg_x(dest), cond);
214ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    } else {
215ba9388c14381400bcc3f6bc327331fbaca12602aAlexandre Rames      ___ Csel(reg_x(dest), reg_x(XZR), reg_x(dest), cond);
216ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    }
217ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
218ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
219ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
220ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::LoadWFromOffset(LoadOperandType type, WRegister dest,
22137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames                                     XRegister base, int32_t offset) {
222ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  switch (type) {
223ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kLoadSignedByte:
224ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Ldrsb(reg_w(dest), MEM_OP(reg_x(base), offset));
225ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
226ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kLoadSignedHalfword:
227ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Ldrsh(reg_w(dest), MEM_OP(reg_x(base), offset));
228ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
229ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kLoadUnsignedByte:
230ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Ldrb(reg_w(dest), MEM_OP(reg_x(base), offset));
231ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
232ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kLoadUnsignedHalfword:
233ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Ldrh(reg_w(dest), MEM_OP(reg_x(base), offset));
234ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
235ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    case kLoadWord:
236ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Ldr(reg_w(dest), MEM_OP(reg_x(base), offset));
237ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      break;
238ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    default:
239ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu        LOG(FATAL) << "UNREACHABLE";
240ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
241ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
242ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
243ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// Note: We can extend this member by adding load type info - see
244ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// sign extended A64 load variants.
24537c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::LoadFromOffset(XRegister dest, XRegister base,
246ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                    int32_t offset) {
247ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK_NE(dest, SP);
248ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Ldr(reg_x(dest), MEM_OP(reg_x(base), offset));
249ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
250ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
25137c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::LoadSFromOffset(SRegister dest, XRegister base,
252ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                     int32_t offset) {
253ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Ldr(reg_s(dest), MEM_OP(reg_x(base), offset));
254ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
255ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
25637c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::LoadDFromOffset(DRegister dest, XRegister base,
257ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                     int32_t offset) {
258ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Ldr(reg_d(dest), MEM_OP(reg_x(base), offset));
259ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
260ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
26137c92df53979f9f6ab83155ab9521d554d717161Alexandre Ramesvoid Arm64Assembler::Load(Arm64ManagedRegister dest, XRegister base,
262ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          int32_t offset, size_t size) {
263ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (dest.IsNoRegister()) {
264ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK_EQ(0u, size) << dest;
265ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (dest.IsWRegister()) {
266ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK_EQ(4u, size) << dest;
267ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    ___ Ldr(reg_w(dest.AsWRegister()), MEM_OP(reg_x(base), offset));
26837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  } else if (dest.IsXRegister()) {
26937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    CHECK_NE(dest.AsXRegister(), SP) << dest;
27075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    if (size == 4u) {
27137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      ___ Ldr(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset));
27275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
27375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      CHECK_EQ(8u, size) << dest;
27437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      ___ Ldr(reg_x(dest.AsXRegister()), MEM_OP(reg_x(base), offset));
27575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
276ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (dest.IsSRegister()) {
277ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    ___ Ldr(reg_s(dest.AsSRegister()), MEM_OP(reg_x(base), offset));
278ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
279ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    CHECK(dest.IsDRegister()) << dest;
280ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    ___ Ldr(reg_d(dest.AsDRegister()), MEM_OP(reg_x(base), offset));
281ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
282ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
283ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
284ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
285ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  return Load(m_dst.AsArm64(), SP, src.Int32Value(), size);
286ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
287ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
28875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::LoadFromThread64(ManagedRegister m_dst, ThreadOffset<8> src, size_t size) {
2899bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  return Load(m_dst.AsArm64(), TR, src.Int32Value(), size);
290ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
291ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
292ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) {
293ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dst = m_dst.AsArm64();
29437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(dst.IsXRegister()) << dst;
29537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), SP, offs.Int32Value());
296ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
297ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
298e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartiervoid Arm64Assembler::LoadRef(ManagedRegister m_dst, ManagedRegister m_base, MemberOffset offs,
2994d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain                             bool unpoison_reference) {
300ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dst = m_dst.AsArm64();
301ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister base = m_base.AsArm64();
30237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(dst.IsXRegister() && base.IsXRegister());
30337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), base.AsXRegister(),
30475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                  offs.Int32Value());
3054d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  if (unpoison_reference) {
30637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    WRegister ref_reg = dst.AsOverlappingWRegister();
3074d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    MaybeUnpoisonHeapReference(reg_w(ref_reg));
308b88f0b16dbaff09a140d2a62b66eca2736ff514bHiroshi Yamauchi  }
309ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
310ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
311ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, Offset offs) {
312ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dst = m_dst.AsArm64();
313ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister base = m_base.AsArm64();
31437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(dst.IsXRegister() && base.IsXRegister());
3150f89dac7336251f7921621a926319d461837840fSerban Constantinescu  // Remove dst and base form the temp list - higher level API uses IP1, IP0.
3160f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::UseScratchRegisterScope temps(vixl_masm_);
31737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  temps.Exclude(reg_x(dst.AsXRegister()), reg_x(base.AsXRegister()));
31837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
319ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
320ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
32175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset<8> offs) {
322ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dst = m_dst.AsArm64();
32337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(dst.IsXRegister()) << dst;
3249bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  LoadFromOffset(dst.AsXRegister(), TR, offs.Int32Value());
325ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
326ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
327ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu// Copying routines.
328ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t size) {
329ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dst = m_dst.AsArm64();
330ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister src = m_src.AsArm64();
331ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (!dst.Equals(src)) {
33237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    if (dst.IsXRegister()) {
33375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      if (size == 4) {
33475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu        CHECK(src.IsWRegister());
33532f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu        ___ Mov(reg_w(dst.AsOverlappingWRegister()), reg_w(src.AsWRegister()));
33675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      } else {
33737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames        if (src.IsXRegister()) {
33837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames          ___ Mov(reg_x(dst.AsXRegister()), reg_x(src.AsXRegister()));
33975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu        } else {
34032f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu          ___ Mov(reg_x(dst.AsXRegister()), reg_x(src.AsOverlappingXRegister()));
34175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu        }
34275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      }
343ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    } else if (dst.IsWRegister()) {
344ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      CHECK(src.IsWRegister()) << src;
345ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Mov(reg_w(dst.AsWRegister()), reg_w(src.AsWRegister()));
346ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    } else if (dst.IsSRegister()) {
347ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      CHECK(src.IsSRegister()) << src;
348ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Fmov(reg_s(dst.AsSRegister()), reg_s(src.AsSRegister()));
349ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    } else {
350ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      CHECK(dst.IsDRegister()) << dst;
351ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      CHECK(src.IsDRegister()) << src;
352ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      ___ Fmov(reg_d(dst.AsDRegister()), reg_d(src.AsDRegister()));
353ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    }
354ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
355ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
356ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
35775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
35875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                          ThreadOffset<8> tr_offs,
359ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                          ManagedRegister m_scratch) {
360ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
36137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
3629bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  LoadFromOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
36337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreToOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
364ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
365ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
36675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::CopyRawPtrToThread64(ThreadOffset<8> tr_offs,
367ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                        FrameOffset fr_offs,
368ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                                        ManagedRegister m_scratch) {
369ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
37037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
37137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadFromOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
3729bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
373ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
374ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
375ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
376ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                             ManagedRegister m_scratch) {
377ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
37837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
37937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(),
38075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                  SP, src.Int32Value());
38137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(),
38275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                 SP, dest.Int32Value());
383ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
384ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
385ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(FrameOffset dest, FrameOffset src,
386ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister m_scratch, size_t size) {
387ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
38837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
389ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK(size == 4 || size == 8) << size;
390ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (size == 4) {
39137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP, src.Int32Value());
39237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP, dest.Int32Value());
393ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (size == 8) {
39437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value());
39537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value());
396ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
397ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
398ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
399ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
400ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
401ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
402ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister m_scratch, size_t size) {
403ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
404ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister base = src_base.AsArm64();
40537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(base.IsXRegister()) << base;
40637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
407ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK(size == 4 || size == 8) << size;
408ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (size == 4) {
40937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadWFromOffset(kLoadWord, scratch.AsWRegister(), base.AsXRegister(),
410ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                   src_offset.Int32Value());
411ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    StoreWToOffset(kStoreWord, scratch.AsWRegister(), SP, dest.Int32Value());
412ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (size == 8) {
41337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), src_offset.Int32Value());
41437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value());
415ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
416ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
417ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
418ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
419ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
420ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(ManagedRegister m_dest_base, Offset dest_offs, FrameOffset src,
421ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister m_scratch, size_t size) {
422ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
423ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister base = m_dest_base.AsArm64();
42437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(base.IsXRegister()) << base;
42537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
426ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK(size == 4 || size == 8) << size;
427ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (size == 4) {
428ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    LoadWFromOffset(kLoadWord, scratch.AsWRegister(), SP, src.Int32Value());
42937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreWToOffset(kStoreWord, scratch.AsWRegister(), base.AsXRegister(),
430ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                   dest_offs.Int32Value());
431ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (size == 8) {
43237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value());
43337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreToOffset(scratch.AsXRegister(), base.AsXRegister(), dest_offs.Int32Value());
434ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
435ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
436ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
437ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
438ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
439ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(FrameOffset /*dst*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
440ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister /*mscratch*/, size_t /*size*/) {
441ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  UNIMPLEMENTED(FATAL) << "Unimplemented Copy() variant";
442ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
443ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
444ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(ManagedRegister m_dest, Offset dest_offset,
445ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister m_src, Offset src_offset,
446ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister m_scratch, size_t size) {
447ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
448ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister src = m_src.AsArm64();
449ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister dest = m_dest.AsArm64();
45037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(dest.IsXRegister()) << dest;
45137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(src.IsXRegister()) << src;
45237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
453ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK(size == 4 || size == 8) << size;
454ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (size == 4) {
45575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    if (scratch.IsWRegister()) {
45637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsXRegister(),
457ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                    src_offset.Int32Value());
45837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsXRegister(),
459ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                   dest_offset.Int32Value());
46075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
46137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), src.AsXRegister(),
46275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                    src_offset.Int32Value());
46337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), dest.AsXRegister(),
46475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                   dest_offset.Int32Value());
46575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
466ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else if (size == 8) {
46737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadFromOffset(scratch.AsXRegister(), src.AsXRegister(), src_offset.Int32Value());
46837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    StoreToOffset(scratch.AsXRegister(), dest.AsXRegister(), dest_offset.Int32Value());
469ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
470ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
471ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
472ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
473ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
474ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Copy(FrameOffset /*dst*/, Offset /*dest_offset*/,
475ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          FrameOffset /*src*/, Offset /*src_offset*/,
476ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu                          ManagedRegister /*scratch*/, size_t /*size*/) {
477ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  UNIMPLEMENTED(FATAL) << "Unimplemented Copy() variant";
478ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
479ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
4806a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogersvoid Arm64Assembler::MemoryBarrier(ManagedRegister m_scratch ATTRIBUTE_UNUSED) {
481ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // TODO: Should we check that m_scratch is IP? - see arm.
482ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Dmb(vixl::InnerShareable, vixl::BarrierAll);
483ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
484ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
485d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampevoid Arm64Assembler::SignExtend(ManagedRegister mreg, size_t size) {
486d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  Arm64ManagedRegister reg = mreg.AsArm64();
487d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  CHECK(size == 1 || size == 2) << size;
488d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  CHECK(reg.IsWRegister()) << reg;
489d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  if (size == 1) {
49032f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu    ___ Sxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
491d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  } else {
49232f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu    ___ Sxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
493d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  }
494ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
495ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
496d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampevoid Arm64Assembler::ZeroExtend(ManagedRegister mreg, size_t size) {
497d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  Arm64ManagedRegister reg = mreg.AsArm64();
498d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  CHECK(size == 1 || size == 2) << size;
499d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  CHECK(reg.IsWRegister()) << reg;
500d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  if (size == 1) {
50132f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu    ___ Uxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
502d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  } else {
50332f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu    ___ Uxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
504d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  }
505ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
506ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
507ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
508ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // TODO: not validating references.
509ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
510ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
511ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
512ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // TODO: not validating references.
513ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
514ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
515ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Call(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) {
516ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister base = m_base.AsArm64();
517ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
51837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(base.IsXRegister()) << base;
51937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
52037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), offs.Int32Value());
52137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Blr(reg_x(scratch.AsXRegister()));
522ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
523ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
524c6ee54e9a9fd67d24c63bd802ef2fe540a4f86a5Andreas Gampevoid Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) {
525c6ee54e9a9fd67d24c63bd802ef2fe540a4f86a5Andreas Gampe  Arm64ManagedRegister base = m_base.AsArm64();
526c6ee54e9a9fd67d24c63bd802ef2fe540a4f86a5Andreas Gampe  Arm64ManagedRegister scratch = m_scratch.AsArm64();
52737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(base.IsXRegister()) << base;
52837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
5290f89dac7336251f7921621a926319d461837840fSerban Constantinescu  // Remove base and scratch form the temp list - higher level API uses IP1, IP0.
5300f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::UseScratchRegisterScope temps(vixl_masm_);
53137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  temps.Exclude(reg_x(base.AsXRegister()), reg_x(scratch.AsXRegister()));
53237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Ldr(reg_x(scratch.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
53337c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Br(reg_x(scratch.AsXRegister()));
534c6ee54e9a9fd67d24c63bd802ef2fe540a4f86a5Andreas Gampe}
535c6ee54e9a9fd67d24c63bd802ef2fe540a4f86a5Andreas Gampe
536ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::Call(FrameOffset base, Offset offs, ManagedRegister m_scratch) {
537ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
53837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
539ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Call *(*(SP + base) + offset)
540e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  LoadFromOffset(scratch.AsXRegister(), SP, base.Int32Value());
54137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadFromOffset(scratch.AsXRegister(), scratch.AsXRegister(), offs.Int32Value());
54237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Blr(reg_x(scratch.AsXRegister()));
543ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
544ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
54575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescuvoid Arm64Assembler::CallFromThread64(ThreadOffset<8> /*offset*/, ManagedRegister /*scratch*/) {
546ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  UNIMPLEMENTED(FATAL) << "Unimplemented Call() variant";
547ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
548ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
549e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartiervoid Arm64Assembler::CreateHandleScopeEntry(
550e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier    ManagedRegister m_out_reg, FrameOffset handle_scope_offs, ManagedRegister m_in_reg,
551e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier    bool null_allowed) {
552ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
553ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
554eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  // For now we only hold stale handle scope entries in x registers.
55537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(in_reg.IsNoRegister() || in_reg.IsXRegister()) << in_reg;
55637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(out_reg.IsXRegister()) << out_reg;
557ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (null_allowed) {
558eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
559eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // the address in the handle scope holding the reference.
560ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
561ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    if (in_reg.IsNoRegister()) {
56237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      LoadWFromOffset(kLoadWord, out_reg.AsOverlappingWRegister(), SP,
563eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                      handle_scope_offs.Int32Value());
564ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu      in_reg = out_reg;
565ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    }
56637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    ___ Cmp(reg_w(in_reg.AsOverlappingWRegister()), 0);
567ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    if (!out_reg.Equals(in_reg)) {
56837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      LoadImmediate(out_reg.AsXRegister(), 0, eq);
569ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    }
57037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), ne);
571ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
57237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), al);
573ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
574ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
575ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
576eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartiervoid Arm64Assembler::CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handle_scope_offset,
577e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier                                            ManagedRegister m_scratch, bool null_allowed) {
578ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
57937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(scratch.IsXRegister()) << scratch;
580ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (null_allowed) {
58137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP,
582eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier                    handle_scope_offset.Int32Value());
583eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
584eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // the address in the handle scope holding the reference.
585eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
58637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    ___ Cmp(reg_w(scratch.AsOverlappingWRegister()), 0);
587ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    // Move this logic in add constants with flags.
58837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), ne);
589ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  } else {
59037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), al);
591ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
59237c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  StoreToOffset(scratch.AsXRegister(), SP, out_off.Int32Value());
593ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
594ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
595eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartiervoid Arm64Assembler::LoadReferenceFromHandleScope(ManagedRegister m_out_reg,
596e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier                                                  ManagedRegister m_in_reg) {
597ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
598ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
59937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(out_reg.IsXRegister()) << out_reg;
60037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  CHECK(in_reg.IsXRegister()) << in_reg;
601ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  vixl::Label exit;
602ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (!out_reg.Equals(in_reg)) {
603ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    // FIXME: Who sets the flags here?
60437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    LoadImmediate(out_reg.AsXRegister(), 0, eq);
605ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
60637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Cbz(reg_x(in_reg.AsXRegister()), &exit);
60737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  LoadFromOffset(out_reg.AsXRegister(), in_reg.AsXRegister(), 0);
608ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Bind(&exit);
609ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
610ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
611ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) {
612ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  CHECK_ALIGNED(stack_adjust, kStackAlignment);
613ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  Arm64ManagedRegister scratch = m_scratch.AsArm64();
614c393d63aa2b8f6984672fdd4de631bbeff14b6a2Alexandre Rames  exception_blocks_.emplace_back(new Arm64Exception(scratch, stack_adjust));
6159bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  LoadFromOffset(scratch.AsXRegister(), TR, Thread::ExceptionOffset<8>().Int32Value());
616c393d63aa2b8f6984672fdd4de631bbeff14b6a2Alexandre Rames  ___ Cbnz(reg_x(scratch.AsXRegister()), exception_blocks_.back()->Entry());
617ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
618ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
619ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) {
6200f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::UseScratchRegisterScope temps(vixl_masm_);
62137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  temps.Exclude(reg_x(exception->scratch_.AsXRegister()));
6220f89dac7336251f7921621a926319d461837840fSerban Constantinescu  vixl::Register temp = temps.AcquireX();
6230f89dac7336251f7921621a926319d461837840fSerban Constantinescu
6240f89dac7336251f7921621a926319d461837840fSerban Constantinescu  // Bind exception poll entry.
625ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Bind(exception->Entry());
626ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  if (exception->stack_adjust_ != 0) {  // Fix up the frame.
627ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu    DecreaseFrameSize(exception->stack_adjust_);
628ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
629ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Pass exception object as argument.
630ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Don't care about preserving X0 as this won't return.
63137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames  ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsXRegister()));
6329bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  ___ Ldr(temp, MEM_OP(reg_x(TR), QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value()));
63375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu
6340f89dac7336251f7921621a926319d461837840fSerban Constantinescu  ___ Blr(temp);
635ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Call should never return.
636ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Brk();
637ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
638ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
63969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xustatic inline dwarf::Reg DWARFReg(CPURegister reg) {
64069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  if (reg.IsFPRegister()) {
64169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    return dwarf::Reg::Arm64Fp(reg.code());
64269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  } else {
64369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    DCHECK_LT(reg.code(), 31u);  // X0 - X30.
64469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    return dwarf::Reg::Arm64Core(reg.code());
64569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
646dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky}
647dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
64869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xuvoid Arm64Assembler::SpillRegisters(vixl::CPURegList registers, int offset) {
64969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  int size = registers.RegisterSizeInBytes();
65069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  const Register sp = vixl_masm_->StackPointer();
65169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  while (registers.Count() >= 2) {
65269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst0 = registers.PopLowestIndex();
65369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst1 = registers.PopLowestIndex();
65469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    ___ Stp(dst0, dst1, MemOperand(sp, offset));
65569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.RelOffset(DWARFReg(dst0), offset);
65669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.RelOffset(DWARFReg(dst1), offset + size);
65769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    offset += 2 * size;
65869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
65969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  if (!registers.IsEmpty()) {
66069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst0 = registers.PopLowestIndex();
66169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    ___ Str(dst0, MemOperand(sp, offset));
66269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.RelOffset(DWARFReg(dst0), offset);
66369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
66469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  DCHECK(registers.IsEmpty());
66569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu}
66669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu
66769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xuvoid Arm64Assembler::UnspillRegisters(vixl::CPURegList registers, int offset) {
66869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  int size = registers.RegisterSizeInBytes();
66969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  const Register sp = vixl_masm_->StackPointer();
67069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  while (registers.Count() >= 2) {
67169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst0 = registers.PopLowestIndex();
67269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst1 = registers.PopLowestIndex();
67369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    ___ Ldp(dst0, dst1, MemOperand(sp, offset));
67469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.Restore(DWARFReg(dst0));
67569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.Restore(DWARFReg(dst1));
67669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    offset += 2 * size;
67769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
67869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  if (!registers.IsEmpty()) {
67969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    const CPURegister& dst0 = registers.PopLowestIndex();
68069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    ___ Ldr(dst0, MemOperand(sp, offset));
68169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    cfi_.Restore(DWARFReg(dst0));
68269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
68369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  DCHECK(registers.IsEmpty());
684dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky}
685dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
686ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescuvoid Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
68769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu                                const std::vector<ManagedRegister>& callee_save_regs,
68869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu                                const ManagedRegisterEntrySpills& entry_spills) {
68969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // Setup VIXL CPURegList for callee-saves.
69069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0);
69169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0);
69269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  for (auto r : callee_save_regs) {
69369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    Arm64ManagedRegister reg = r.AsArm64();
69469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    if (reg.IsXRegister()) {
69569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      core_reg_list.Combine(reg_x(reg.AsXRegister()).code());
69669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    } else {
69769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      DCHECK(reg.IsDRegister());
69869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      fp_reg_list.Combine(reg_d(reg.AsDRegister()).code());
69969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    }
70069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
70169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  size_t core_reg_size = core_reg_list.TotalSizeInBytes();
70269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  size_t fp_reg_size = fp_reg_list.TotalSizeInBytes();
70369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu
70469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // Increase frame to required size.
70569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  DCHECK_ALIGNED(frame_size, kStackAlignment);
706e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  DCHECK_GE(frame_size, core_reg_size + fp_reg_size + kArm64PointerSize);
707b551fdcda9eb128c80de37c4fb978968bec6d4b3Zheng Xu  IncreaseFrameSize(frame_size);
708b551fdcda9eb128c80de37c4fb978968bec6d4b3Zheng Xu
70969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // Save callee-saves.
71069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  SpillRegisters(core_reg_list, frame_size - core_reg_size);
71169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  SpillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size);
7127cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
7139bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR)));
714ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
715e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  // Write ArtMethod*
71669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  DCHECK(X0 == method_reg.AsArm64().AsXRegister());
717e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  StoreToOffset(X0, SP, 0);
718ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
71975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  // Write out entry spills
720e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  int32_t offset = frame_size + kArm64PointerSize;
721ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  for (size_t i = 0; i < entry_spills.size(); ++i) {
72275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    Arm64ManagedRegister reg = entry_spills.at(i).AsArm64();
72375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    if (reg.IsNoRegister()) {
72475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      // only increment stack offset.
72575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      ManagedRegisterSpill spill = entry_spills.at(i);
72675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      offset += spill.getSize();
72737c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames    } else if (reg.IsXRegister()) {
72837c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      StoreToOffset(reg.AsXRegister(), SP, offset);
72975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      offset += 8;
73075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else if (reg.IsWRegister()) {
73175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      StoreWToOffset(kStoreWord, reg.AsWRegister(), SP, offset);
73275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      offset += 4;
73375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else if (reg.IsDRegister()) {
73475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      StoreDToOffset(reg.AsDRegister(), SP, offset);
73575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      offset += 8;
73675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else if (reg.IsSRegister()) {
73775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      StoreSToOffset(reg.AsSRegister(), SP, offset);
73875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      offset += 4;
73975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
740ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  }
741ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
742ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
74369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xuvoid Arm64Assembler::RemoveFrame(size_t frame_size,
74469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu                                 const std::vector<ManagedRegister>& callee_save_regs) {
74569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // Setup VIXL CPURegList for callee-saves.
74669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0);
74769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0);
74869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  for (auto r : callee_save_regs) {
74969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    Arm64ManagedRegister reg = r.AsArm64();
75069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    if (reg.IsXRegister()) {
75169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      core_reg_list.Combine(reg_x(reg.AsXRegister()).code());
75269a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    } else {
75369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      DCHECK(reg.IsDRegister());
75469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu      fp_reg_list.Combine(reg_d(reg.AsDRegister()).code());
75569a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu    }
75669a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  }
75769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  size_t core_reg_size = core_reg_list.TotalSizeInBytes();
75869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  size_t fp_reg_size = fp_reg_list.TotalSizeInBytes();
75969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu
76069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // For now we only check that the size of the frame is large enough to hold spills and method
76169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // reference.
762e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier  DCHECK_GE(frame_size, core_reg_size + fp_reg_size + kArm64PointerSize);
76369a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  DCHECK_ALIGNED(frame_size, kStackAlignment);
76469a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu
7659bd88b0933a372e6a7b64b850868e6a7998567e2Serban Constantinescu  DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR)));
76675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu
76769a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  cfi_.RememberState();
76869a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu
76969a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  // Restore callee-saves.
77069a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  UnspillRegisters(core_reg_list, frame_size - core_reg_size);
77169a503050fb8a7b3a79b2cd2cdc2d8fbc594575dZheng Xu  UnspillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size);
7727cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
773b551fdcda9eb128c80de37c4fb978968bec6d4b3Zheng Xu  // Decrease frame size to start of callee saved regs.
774b551fdcda9eb128c80de37c4fb978968bec6d4b3Zheng Xu  DecreaseFrameSize(frame_size);
775b551fdcda9eb128c80de37c4fb978968bec6d4b3Zheng Xu
776ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  // Pop callee saved and return to LR.
777ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu  ___ Ret();
778dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky
779dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  // The CFI should be restored for any code that follows the exit block.
780dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.RestoreState();
781dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  cfi_.DefCFAOffset(frame_size);
782ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}
783ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu
7844d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillainvoid Arm64Assembler::PoisonHeapReference(vixl::Register reg) {
7854d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  DCHECK(reg.IsW());
7864d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  // reg = -reg.
7874d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  ___ Neg(reg, vixl::Operand(reg));
7884d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain}
7894d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
7904d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillainvoid Arm64Assembler::UnpoisonHeapReference(vixl::Register reg) {
7914d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  DCHECK(reg.IsW());
7924d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  // reg = -reg.
7934d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  ___ Neg(reg, vixl::Operand(reg));
7944d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain}
7954d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
7964d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillainvoid Arm64Assembler::MaybeUnpoisonHeapReference(vixl::Register reg) {
7974d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  if (kPoisonHeapReferences) {
7984d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    UnpoisonHeapReference(reg);
7994d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  }
8004d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain}
8014d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
8024d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef ___
8034d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
804ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}  // namespace arm64
805ed8dd492e43cbaaa435c4892447072c84dbaf2dcSerban Constantinescu}  // namespace art
806