macro-assembler-aarch64.cc revision 7e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67
1b78f13911bfe6eda303e91ef215c87a165aae8aeAlexandre Rames// Copyright 2015, VIXL authors
2ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// All rights reserved.
3ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//
4ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// Redistribution and use in source and binary forms, with or without
5ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// modification, are permitted provided that the following conditions are met:
6ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//
7ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//   * Redistributions of source code must retain the above copyright notice,
8ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//     this list of conditions and the following disclaimer.
9ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//   * Redistributions in binary form must reproduce the above copyright notice,
10ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//     this list of conditions and the following disclaimer in the documentation
11ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//     and/or other materials provided with the distribution.
12ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//   * Neither the name of ARM Limited nor the names of its contributors may be
13ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//     used to endorse or promote products derived from this software without
14ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//     specific prior written permission.
15ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl//
16ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2778973f258039f6e96eba85f1b5ecdb14b3c51dbbPierre Langlois#include <cctype>
28684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl
29b49bdb7996e603555eba4c8b56c7325e3e737ab6Alexandre Rames#include "macro-assembler-aarch64.h"
305289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
31ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlnamespace vixl {
3288c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisnamespace aarch64 {
33ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
34c68cb64496485710cdb5b8480f8fee287058c93farmvixl
355289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid Pool::Release() {
365289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (--monitor_ == 0) {
375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    // Ensure the pool has not been blocked for too long.
3888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(masm_->GetCursorOffset() < checkpoint_);
395289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
435289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {
445289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);
455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  checkpoint_ = checkpoint;
465289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
475289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
485289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
496e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlLiteralPool::LiteralPool(MacroAssembler* masm)
500f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    : Pool(masm),
510f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      size_(0),
520f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      first_use_(-1),
530f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      recommended_checkpoint_(kNoCheckpointRequired) {}
54c68cb64496485710cdb5b8480f8fee287058c93farmvixl
55c68cb64496485710cdb5b8480f8fee287058c93farmvixl
56c68cb64496485710cdb5b8480f8fee287058c93farmvixlLiteralPool::~LiteralPool() {
57c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(IsEmpty());
58c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(!IsBlocked());
59db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  for (std::vector<RawLiteral*>::iterator it = deleted_on_destruction_.begin();
60db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl       it != deleted_on_destruction_.end();
61db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl       it++) {
62db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    delete *it;
63db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  }
64c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
65c68cb64496485710cdb5b8480f8fee287058c93farmvixl
66c68cb64496485710cdb5b8480f8fee287058c93farmvixl
67c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid LiteralPool::Reset() {
68c68cb64496485710cdb5b8480f8fee287058c93farmvixl  std::vector<RawLiteral*>::iterator it, end;
69c68cb64496485710cdb5b8480f8fee287058c93farmvixl  for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
70db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    RawLiteral* literal = *it;
71db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    if (literal->deletion_policy_ == RawLiteral::kDeletedOnPlacementByPool) {
72db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl      delete literal;
73db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    }
74c68cb64496485710cdb5b8480f8fee287058c93farmvixl  }
75c68cb64496485710cdb5b8480f8fee287058c93farmvixl  entries_.clear();
765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  size_ = 0;
77c68cb64496485710cdb5b8480f8fee287058c93farmvixl  first_use_ = -1;
785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Pool::Reset();
795289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  recommended_checkpoint_ = kNoCheckpointRequired;
80c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
81c68cb64496485710cdb5b8480f8fee287058c93farmvixl
82c68cb64496485710cdb5b8480f8fee287058c93farmvixl
83c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {
84c68cb64496485710cdb5b8480f8fee287058c93farmvixl  if (IsEmpty() || IsBlocked()) return;
85c68cb64496485710cdb5b8480f8fee287058c93farmvixl
8688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ptrdiff_t distance = masm_->GetCursorOffset() + amount - first_use_;
87c68cb64496485710cdb5b8480f8fee287058c93farmvixl  if (distance >= kRecommendedLiteralPoolRange) {
88c68cb64496485710cdb5b8480f8fee287058c93farmvixl    Emit(option);
89c68cb64496485710cdb5b8480f8fee287058c93farmvixl  }
90c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
91c68cb64496485710cdb5b8480f8fee287058c93farmvixl
92c68cb64496485710cdb5b8480f8fee287058c93farmvixl
9307d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// We use a subclass to access the protected `ExactAssemblyScope` constructor
9407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// giving us control over the pools. This allows us to use this scope within
9507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// code emitting pools without creating a circular dependency.
9607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// We keep the constructor private to restrict usage of this helper class.
9707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Ramesclass ExactAssemblyScopeWithoutPoolsCheck : public ExactAssemblyScope {
9807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames private:
9907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler* masm, size_t size)
10007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames      : ExactAssemblyScope(masm,
10107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           size,
10207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           ExactAssemblyScope::kExactSize,
10307d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           ExactAssemblyScope::kIgnorePools) {}
10407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
10507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  friend void LiteralPool::Emit(LiteralPool::EmitOption);
10607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  friend void VeneerPool::Emit(VeneerPool::EmitOption, size_t);
10707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames};
10807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
10907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
110c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid LiteralPool::Emit(EmitOption option) {
111c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // There is an issue if we are asked to emit a blocked or empty pool.
112c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(!IsBlocked());
113c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(!IsEmpty());
114c68cb64496485710cdb5b8480f8fee287058c93farmvixl
11588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  size_t pool_size = GetSize();
116c68cb64496485710cdb5b8480f8fee287058c93farmvixl  size_t emit_size = pool_size;
117c68cb64496485710cdb5b8480f8fee287058c93farmvixl  if (option == kBranchRequired) emit_size += kInstructionSize;
118c68cb64496485710cdb5b8480f8fee287058c93farmvixl  Label end_of_pool;
119c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(emit_size % kInstructionSize == 0);
121de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames  {
122de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    CodeBufferCheckScope guard(masm_,
123de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                               emit_size,
124de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                               CodeBufferCheckScope::kCheck,
125de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                               CodeBufferCheckScope::kExactSize);
126de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames#ifdef VIXL_DEBUG
127de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    // Also explicitly disallow usage of the `MacroAssembler` here.
128de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    masm_->SetAllowMacroInstructions(false);
129de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames#endif
130de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    if (option == kBranchRequired) {
13107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames      ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
132de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      masm_->b(&end_of_pool);
133de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    }
134c68cb64496485710cdb5b8480f8fee287058c93farmvixl
135de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    {
136de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      // Marker indicating the size of the literal pool in 32-bit words.
137de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);
13807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames      ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
139de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      masm_->ldr(xzr, static_cast<int>(pool_size / kWRegSizeInBytes));
140de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    }
141c68cb64496485710cdb5b8480f8fee287058c93farmvixl
142de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    // Now populate the literal pool.
143de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    std::vector<RawLiteral*>::iterator it, end;
144de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {
145de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      VIXL_ASSERT((*it)->IsUsed());
146de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      masm_->place(*it);
147de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    }
148c68cb64496485710cdb5b8480f8fee287058c93farmvixl
149de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    if (option == kBranchRequired) masm_->bind(&end_of_pool);
150de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames#ifdef VIXL_DEBUG
151de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames    masm_->SetAllowMacroInstructions(true);
152de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames#endif
153de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames  }
154c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Reset();
1565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
1575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
159db6443499376478f5281607a3923e6ffc4c8d8ecarmvixlvoid LiteralPool::AddEntry(RawLiteral* literal) {
160db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  // A literal must be registered immediately before its first use. Here we
161db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  // cannot control that it is its first use, but we check no code has been
162db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  // emitted since its last use.
16388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(masm_->GetCursorOffset() == literal->GetLastUse());
1645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
16588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  UpdateFirstUse(masm_->GetCursorOffset());
16688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(masm_->GetCursorOffset() >= first_use_);
1675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  entries_.push_back(literal);
16888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  size_ += literal->GetSize();
169db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl}
170db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl
1715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
172db6443499376478f5281607a3923e6ffc4c8d8ecarmvixlvoid LiteralPool::UpdateFirstUse(ptrdiff_t use_position) {
173db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  first_use_ = std::min(first_use_, use_position);
174db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  if (first_use_ == -1) {
175db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    first_use_ = use_position;
17688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    SetNextRecommendedCheckpoint(GetNextRecommendedCheckpoint());
177db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);
178db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  } else {
179db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl    VIXL_ASSERT(use_position > first_use_);
180db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  }
1815289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
1825289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1845289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::Reset() {
1855289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Pool::Reset();
1865289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  unresolved_branches_.Reset();
1875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
1885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::Release() {
1915289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (--monitor_ == 0) {
1925289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    VIXL_ASSERT(IsEmpty() ||
19388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                masm_->GetCursorOffset() <
19488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    unresolved_branches_.GetFirstLimit());
1955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
196c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
197c68cb64496485710cdb5b8480f8fee287058c93farmvixl
198c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1995289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,
2005289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                          Label* label,
2015289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                          ImmBranchType branch_type) {
2025289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!label->IsBound());
2035289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);
2045289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  unresolved_branches_.insert(branch_info);
2055289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  UpdateNextCheckPoint();
2065289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // TODO: In debug mode register the label with the assembler to make sure it
2075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // is bound with masm Bind and not asm bind.
2085289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
2095289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2105289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2115289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {
212c68cb64496485710cdb5b8480f8fee287058c93farmvixl  if (IsEmpty()) {
2135289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);
2145289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
215c68cb64496485710cdb5b8480f8fee287058c93farmvixl  }
216c68cb64496485710cdb5b8480f8fee287058c93farmvixl
2175289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsLinked()) {
2185289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label::LabelLinksIterator links_it(label);
2195289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    for (; !links_it.Done(); links_it.Advance()) {
2205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      ptrdiff_t link_offset = *links_it.Current();
22188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Instruction* link = masm_->GetInstructionAt(link_offset);
222c68cb64496485710cdb5b8480f8fee287058c93farmvixl
2235289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // ADR instructions are not handled.
22488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (BranchTypeUsesVeneers(link->GetBranchType())) {
22588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        BranchInfo branch_info(link_offset, label, link->GetBranchType());
2265289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        unresolved_branches_.erase(branch_info);
2275289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      }
2285289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
2295289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
2305289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2315289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  UpdateNextCheckPoint();
2325289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
2335289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2345289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2357e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouvelibool VeneerPool::ShouldEmitVeneer(int64_t first_unreacheable_pc,
2367e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouveli                                  size_t amount) {
2375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  ptrdiff_t offset =
23888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      kPoolNonVeneerCodeSize + amount + GetMaxSize() + GetOtherPoolsMaxSize();
2397e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouveli  return (masm_->GetCursorOffset() + offset) > first_unreacheable_pc;
2405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
2415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2435289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {
2445289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (IsEmpty()) return;
2455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2467e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouveli  VIXL_ASSERT(masm_->GetCursorOffset() + kPoolNonVeneerCodeSize <
2477e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouveli              unresolved_branches_.GetFirstLimit());
2485289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2495289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (IsBlocked()) return;
2505289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2515289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (ShouldEmitVeneers(amount)) {
2525289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Emit(option, amount);
2535289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
2545289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    UpdateNextCheckPoint();
2555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
2565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
2575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2595289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid VeneerPool::Emit(EmitOption option, size_t amount) {
2605289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // There is an issue if we are asked to emit a blocked or empty pool.
2615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!IsBlocked());
2625289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!IsEmpty());
2635289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Label end;
2655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (option == kBranchRequired) {
26607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
2675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    masm_->b(&end);
2685289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
2695289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2705289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // We want to avoid generating veneer pools too often, so generate veneers for
2715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // branches that don't immediately require a veneer but will soon go out of
2725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // range.
2735289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  static const size_t kVeneerEmissionMargin = 1 * KBytes;
2745289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2755289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {
2765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    BranchInfo* branch_info = it.Current();
2777e0f1ebcf5ac1f83fd4b85a5b8f2e80dc991ed67Georgia Kouveli    if (ShouldEmitVeneer(branch_info->first_unreacheable_pc_,
2785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                         amount + kVeneerEmissionMargin)) {
279de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      CodeBufferCheckScope scope(masm_,
280de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                                 kVeneerCodeSize,
281de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                                 CodeBufferCheckScope::kCheck,
282de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames                                 CodeBufferCheckScope::kExactSize);
2835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      ptrdiff_t branch_pos = branch_info->pc_offset_;
28488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Instruction* branch = masm_->GetInstructionAt(branch_pos);
2855289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      Label* label = branch_info->label_;
2865289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // Patch the branch to point to the current position, and emit a branch
2885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // to the label.
2895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      Instruction* veneer = masm_->GetCursorAddress<Instruction*>();
2905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      branch->SetImmPCOffsetTarget(veneer);
291de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      {
29207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames        ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);
293de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames        masm_->b(label);
294de5bb0beb4a3342bb9f0d7e7fe16737a171517b0Alexandre Rames      }
2955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2965289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // Update the label. The branch patched does not point to it any longer.
2975289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      label->DeleteLink(branch_pos);
2985289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2995289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      it.DeleteCurrentAndAdvance();
3005289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else {
3015289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      it.AdvanceToNextType();
3025289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
3035289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
3045289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
3055289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  UpdateNextCheckPoint();
3065289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
3075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  masm_->bind(&end);
308c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
309c68cb64496485710cdb5b8480f8fee287058c93farmvixl
310c68cb64496485710cdb5b8480f8fee287058c93farmvixl
311f2f550c0bfd0f15a4d1c51ff06ec898536f14205Alexandre RamesMacroAssembler::MacroAssembler(PositionIndependentCodeOption pic)
312f2f550c0bfd0f15a4d1c51ff06ec898536f14205Alexandre Rames    : Assembler(pic),
313b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames#ifdef VIXL_DEBUG
314b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      allow_macro_instructions_(true),
315b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames#endif
3161e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
317b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      sp_(sp),
318b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      tmp_list_(ip0, ip1),
319b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      fptmp_list_(d31),
320e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      current_scratch_scope_(NULL),
321b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      literal_pool_(this),
322b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      veneer_pool_(this),
323b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames      recommended_checkpoint_(Pool::kNoCheckpointRequired) {
324b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames  checkpoint_ = GetNextCheckPoint();
325fd09817b8770a5e3a64a6fe4fefe85cc29805cd7Alexandre Rames#ifndef VIXL_DEBUG
326fd09817b8770a5e3a64a6fe4fefe85cc29805cd7Alexandre Rames  USE(allow_macro_instructions_);
327fd09817b8770a5e3a64a6fe4fefe85cc29805cd7Alexandre Rames#endif
328b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames}
329b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames
330b0d7672aa9d5163ffce32f14a0fc1aa32f516f89Alexandre Rames
331c68cb64496485710cdb5b8480f8fee287058c93farmvixlMacroAssembler::MacroAssembler(size_t capacity,
332c68cb64496485710cdb5b8480f8fee287058c93farmvixl                               PositionIndependentCodeOption pic)
333c68cb64496485710cdb5b8480f8fee287058c93farmvixl    : Assembler(capacity, pic),
334330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl#ifdef VIXL_DEBUG
335c68cb64496485710cdb5b8480f8fee287058c93farmvixl      allow_macro_instructions_(true),
336c68cb64496485710cdb5b8480f8fee287058c93farmvixl#endif
3371e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
338c68cb64496485710cdb5b8480f8fee287058c93farmvixl      sp_(sp),
339c68cb64496485710cdb5b8480f8fee287058c93farmvixl      tmp_list_(ip0, ip1),
340c68cb64496485710cdb5b8480f8fee287058c93farmvixl      fptmp_list_(d31),
341e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      current_scratch_scope_(NULL),
3425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      literal_pool_(this),
343db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl      veneer_pool_(this),
344db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl      recommended_checkpoint_(Pool::kNoCheckpointRequired) {
34588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  checkpoint_ = GetNextCheckPoint();
346c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
347c68cb64496485710cdb5b8480f8fee287058c93farmvixl
348c68cb64496485710cdb5b8480f8fee287058c93farmvixl
3490f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlMacroAssembler::MacroAssembler(byte* buffer,
350c68cb64496485710cdb5b8480f8fee287058c93farmvixl                               size_t capacity,
351c68cb64496485710cdb5b8480f8fee287058c93farmvixl                               PositionIndependentCodeOption pic)
352c68cb64496485710cdb5b8480f8fee287058c93farmvixl    : Assembler(buffer, capacity, pic),
353330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl#ifdef VIXL_DEBUG
354c68cb64496485710cdb5b8480f8fee287058c93farmvixl      allow_macro_instructions_(true),
355c68cb64496485710cdb5b8480f8fee287058c93farmvixl#endif
3561e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),
357c68cb64496485710cdb5b8480f8fee287058c93farmvixl      sp_(sp),
358c68cb64496485710cdb5b8480f8fee287058c93farmvixl      tmp_list_(ip0, ip1),
359c68cb64496485710cdb5b8480f8fee287058c93farmvixl      fptmp_list_(d31),
360e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      current_scratch_scope_(NULL),
3615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      literal_pool_(this),
362db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl      veneer_pool_(this),
363db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl      recommended_checkpoint_(Pool::kNoCheckpointRequired) {
36488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  checkpoint_ = GetNextCheckPoint();
365c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
366c68cb64496485710cdb5b8480f8fee287058c93farmvixl
367c68cb64496485710cdb5b8480f8fee287058c93farmvixl
3680f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlMacroAssembler::~MacroAssembler() {}
369c68cb64496485710cdb5b8480f8fee287058c93farmvixl
370c68cb64496485710cdb5b8480f8fee287058c93farmvixl
371c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid MacroAssembler::Reset() {
372c68cb64496485710cdb5b8480f8fee287058c93farmvixl  Assembler::Reset();
373c68cb64496485710cdb5b8480f8fee287058c93farmvixl
374c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(!literal_pool_.IsBlocked());
375c68cb64496485710cdb5b8480f8fee287058c93farmvixl  literal_pool_.Reset();
3765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  veneer_pool_.Reset();
377c68cb64496485710cdb5b8480f8fee287058c93farmvixl
37888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  checkpoint_ = GetNextCheckPoint();
379c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
380c68cb64496485710cdb5b8480f8fee287058c93farmvixl
381c68cb64496485710cdb5b8480f8fee287058c93farmvixl
382c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid MacroAssembler::FinalizeCode() {
383c68cb64496485710cdb5b8480f8fee287058c93farmvixl  if (!literal_pool_.IsEmpty()) literal_pool_.Emit();
3845289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(veneer_pool_.IsEmpty());
385c68cb64496485710cdb5b8480f8fee287058c93farmvixl
386c68cb64496485710cdb5b8480f8fee287058c93farmvixl  Assembler::FinalizeCode();
387c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
388c68cb64496485710cdb5b8480f8fee287058c93farmvixl
389c68cb64496485710cdb5b8480f8fee287058c93farmvixl
3905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::CheckEmitFor(size_t amount) {
3919fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Rames  CheckEmitPoolsFor(amount);
3926a049f97861bd71c69d81f643e42308d28c5de31Alexandre Rames  GetBuffer()->EnsureSpaceFor(amount);
3939fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Rames}
3949fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Rames
3955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
3969fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Ramesvoid MacroAssembler::CheckEmitPoolsFor(size_t amount) {
3979fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Rames  literal_pool_.CheckEmitFor(amount);
3989fbd11bbc6a56071f455df28e08854a848f46c3bAlexandre Rames  veneer_pool_.CheckEmitFor(amount);
39988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  checkpoint_ = GetNextCheckPoint();
4005289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
4015289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
4025289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
403330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixlint MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,
4040f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                        const Register& rd,
405330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl                                        uint64_t imm) {
406330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  bool emit_code = (masm != NULL);
40788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(IsUint32(imm) || IsInt32(imm) || rd.Is64Bits());
408330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // The worst case for size is mov 64-bit immediate to sp:
409330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  * up to 4 instructions to materialise the constant
410330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  * 1 instruction to move to sp
411330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  MacroEmissionCheckScope guard(masm);
412330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
413330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // Immediates on Aarch64 can be produced using an initial value, and zero to
414330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // three move keep operations.
415330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //
416330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // Initial values can be generated with:
417330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  1. 64-bit move zero (movz).
418330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  2. 32-bit move inverted (movn).
419330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  3. 64-bit move inverted.
420330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  4. 32-bit orr immediate.
421330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //  5. 64-bit orr immediate.
422330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // Move-keep may then be used to modify each of the 16-bit half words.
423330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  //
424330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // The code below supports all five initial value generators, and
425330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // applying move-keep operations to move-zero and move-inverted initial
426330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // values.
427330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
428330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // Try to move the immediate in one instruction, and if that fails, switch to
429330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // using multiple instructions.
430330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  if (OneInstrMoveImmediateHelper(masm, rd, imm)) {
431330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    return 1;
432330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  } else {
433330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    int instruction_count = 0;
43488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    unsigned reg_size = rd.GetSizeInBits();
435330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
436330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Generic immediate case. Imm will be represented by
437330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    //   [imm3, imm2, imm1, imm0], where each imm is 16 bits.
438330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // A move-zero or move-inverted is generated for the first non-zero or
439330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // non-0xffff immX, and a move-keep for subsequent non-zero immX.
440330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
441330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    uint64_t ignored_halfword = 0;
442330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    bool invert_move = false;
443330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // If the number of 0xffff halfwords is greater than the number of 0x0000
444330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // halfwords, it's more efficient to use move-inverted.
445330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (CountClearHalfWords(~imm, reg_size) >
446330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl        CountClearHalfWords(imm, reg_size)) {
447330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      ignored_halfword = 0xffff;
448330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      invert_move = true;
449330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
450330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
451330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Mov instructions can't move values into the stack pointer, so set up a
452330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // temporary register, if needed.
453330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    UseScratchRegisterScope temps;
454330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    Register temp;
455330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (emit_code) {
456330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      temps.Open(masm);
457330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
458330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
459330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
460330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Iterate through the halfwords. Use movn/movz for the first non-ignored
461330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // halfword, and movk for subsequent halfwords.
462330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    VIXL_ASSERT((reg_size % 16) == 0);
463330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    bool first_mov_done = false;
4640f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    for (unsigned i = 0; i < (reg_size / 16); i++) {
465330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      uint64_t imm16 = (imm >> (16 * i)) & 0xffff;
466330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      if (imm16 != ignored_halfword) {
467330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl        if (!first_mov_done) {
468330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          if (invert_move) {
469330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl            if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);
470330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl            instruction_count++;
471330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          } else {
472330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl            if (emit_code) masm->movz(temp, imm16, 16 * i);
473330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl            instruction_count++;
474330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          }
475330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          first_mov_done = true;
476330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl        } else {
477330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          // Construct a wider constant.
478330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          if (emit_code) masm->movk(temp, imm16, 16 * i);
479330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl          instruction_count++;
480330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl        }
481330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      }
482330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
483330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
484330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    VIXL_ASSERT(first_mov_done);
485330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
486330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Move the temporary if the original destination register was the stack
487330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // pointer.
488330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (rd.IsSP()) {
489330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      if (emit_code) masm->mov(rd, temp);
490330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      instruction_count++;
491330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
492330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    return instruction_count;
493330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  }
494330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl}
495330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
496330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
497330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixlbool MacroAssembler::OneInstrMoveImmediateHelper(MacroAssembler* masm,
498330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl                                                 const Register& dst,
499330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl                                                 int64_t imm) {
500330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  bool emit_code = masm != NULL;
501330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  unsigned n, imm_s, imm_r;
50288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int reg_size = dst.GetSizeInBits();
503330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
504330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
505330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Immediate can be represented in a move zero instruction. Movz can't write
506330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // to the stack pointer.
507330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (emit_code) {
508330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      masm->movz(dst, imm);
509330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
510330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    return true;
511330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  } else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
512330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Immediate can be represented in a move negative instruction. Movn can't
513330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // write to the stack pointer.
514330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (emit_code) {
515330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl      masm->movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
516330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
517330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    return true;
518330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
519330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Immediate can be represented in a logical orr instruction.
520330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    VIXL_ASSERT(!dst.IsZero());
521330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    if (emit_code) {
5220f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->LogicalImmediate(dst,
5230f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             AppropriateZeroRegFor(dst),
5240f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             n,
5250f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             imm_s,
5260f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             imm_r,
5270f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             ORR);
528330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    }
529330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    return true;
530330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  }
531330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  return false;
532330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl}
533330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
534330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
535b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
536b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&
537b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl              ((bit == -1) || (type >= kBranchTypeFirstUsingBit)));
538b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
539b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    B(static_cast<Condition>(type), label);
540b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else {
541b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    switch (type) {
5420f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case always:
5430f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        B(label);
5440f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
5450f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case never:
5460f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
5470f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case reg_zero:
5480f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        Cbz(reg, label);
5490f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
5500f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case reg_not_zero:
5510f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        Cbnz(reg, label);
5520f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
5530f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case reg_bit_clear:
5540f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        Tbz(reg, bit, label);
5550f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
5560f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      case reg_bit_set:
5570f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        Tbnz(reg, bit, label);
5580f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl        break;
559b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      default:
560b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl        VIXL_UNREACHABLE();
561b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    }
562b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
563b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
564b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
5655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5665289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::B(Label* label) {
5675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  SingleEmissionCheckScope guard(this);
5685289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  b(label);
5695289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
5705289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::B(Label* label, Condition cond) {
5735289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
5745289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT((cond != al) && (cond != nv));
5755289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  EmissionCheckScope guard(this, 2 * kInstructionSize);
5765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5775289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
5785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label done;
5795289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(&done, InvertCondition(cond));
5805289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label);
5815289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bind(&done);
5825289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
5835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (!label->IsBound()) {
58488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
5855289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            label,
5865289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            CondBranchType);
5875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
5885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label, cond);
5895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
5905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
5915289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5925289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5935289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Cbnz(const Register& rt, Label* label) {
5945289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
5955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!rt.IsZero());
5965289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  EmissionCheckScope guard(this, 2 * kInstructionSize);
5975289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
5985289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
5995289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label done;
6005289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    cbz(rt, &done);
6015289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label);
6025289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bind(&done);
6035289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
6045289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (!label->IsBound()) {
60588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
6065289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            label,
6075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            CompareBranchType);
6085289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
6095289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    cbnz(rt, label);
6105289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
6115289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6125289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6135289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6145289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Cbz(const Register& rt, Label* label) {
6155289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
6165289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!rt.IsZero());
6175289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  EmissionCheckScope guard(this, 2 * kInstructionSize);
6185289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6195289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
6205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label done;
6215289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    cbnz(rt, &done);
6225289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label);
6235289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bind(&done);
6245289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
6255289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (!label->IsBound()) {
62688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
6275289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            label,
6285289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            CompareBranchType);
6295289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
6305289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    cbz(rt, label);
6315289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
6325289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6335289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6345289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6355289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
6365289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
6375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!rt.IsZero());
6385289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  EmissionCheckScope guard(this, 2 * kInstructionSize);
6395289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
6415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label done;
6425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    tbz(rt, bit_pos, &done);
6435289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label);
6445289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bind(&done);
6455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
6465289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (!label->IsBound()) {
64788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
6485289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            label,
6495289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            TestBranchType);
6505289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
6515289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    tbnz(rt, bit_pos, label);
6525289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
6535289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6545289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
6575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
6585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(!rt.IsZero());
6595289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  EmissionCheckScope guard(this, 2 * kInstructionSize);
6605289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {
6625289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Label done;
6635289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    tbnz(rt, bit_pos, &done);
6645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    b(label);
6655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bind(&done);
6665289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
6675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (!label->IsBound()) {
66888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),
6695289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            label,
6705289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                            TestBranchType);
6715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
6725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    tbz(rt, bit_pos, label);
6735289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
6745289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6755289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6775289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Bind(Label* label) {
6785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
6795289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
6805289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  bind(label);
6815289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6825289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6845289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl// Bind a label to a specified offset from the start of the buffer.
6855289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {
6865289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
6875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);
6885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Assembler::BindToOffset(label, offset);
6895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
6905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
6915289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
692ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::And(const Register& rd,
693ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
694f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         const Operand& operand) {
695b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
696f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  LogicalMacro(rd, rn, operand, AND);
697f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
698f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
699f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
700f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Ands(const Register& rd,
701f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
702f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
703b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
704f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  LogicalMacro(rd, rn, operand, ANDS);
705ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
706ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
707ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
7080f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Tst(const Register& rn, const Operand& operand) {
709b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
710f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Ands(AppropriateZeroRegFor(rn), rn, operand);
711ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
712ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
713ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
714ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Bic(const Register& rd,
715ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
716f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         const Operand& operand) {
717b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
718f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  LogicalMacro(rd, rn, operand, BIC);
719f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
720f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
721f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
722f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Bics(const Register& rd,
723f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
724f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
725b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
726f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  LogicalMacro(rd, rn, operand, BICS);
727ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
728ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
729ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
730ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Orr(const Register& rd,
731ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
732ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Operand& operand) {
733b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
734ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  LogicalMacro(rd, rn, operand, ORR);
735ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
736ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
737ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
738ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Orn(const Register& rd,
739ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
740ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Operand& operand) {
741b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
742ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  LogicalMacro(rd, rn, operand, ORN);
743ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
744ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
745ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
746ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Eor(const Register& rd,
747ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
748ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Operand& operand) {
749b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
750ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  LogicalMacro(rd, rn, operand, EOR);
751ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
752ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
753ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
754ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Eon(const Register& rd,
755ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
756ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Operand& operand) {
757b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
758ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  LogicalMacro(rd, rn, operand, EON);
759ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
760ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
761ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
762ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::LogicalMacro(const Register& rd,
763ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                  const Register& rn,
764ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                  const Operand& operand,
765ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                  LogicalOp op) {
766c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // The worst case for size is logical immediate to sp:
767c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
768c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction to do the operation
769c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction to move to sp
770c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
771b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  UseScratchRegisterScope temps(this);
772b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
773ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (operand.IsImmediate()) {
77485919f840e8ddd06573def57eb587cc77661e7d0Jacob Bramley    uint64_t immediate = operand.GetImmediate();
77588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    unsigned reg_size = rd.GetSizeInBits();
776ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
777ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // If the operation is NOT, invert the operation and immediate.
778ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if ((op & NOT) == NOT) {
779ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      op = static_cast<LogicalOp>(op & ~NOT);
780ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      immediate = ~immediate;
781ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
782ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
7834a102baf640077d6794c0b33bb976f94b86c532barmvixl    // Ignore the top 32 bits of an immediate if we're moving to a W register.
7844a102baf640077d6794c0b33bb976f94b86c532barmvixl    if (rd.Is32Bits()) {
7854a102baf640077d6794c0b33bb976f94b86c532barmvixl      // Check that the top 32 bits are consistent.
7864a102baf640077d6794c0b33bb976f94b86c532barmvixl      VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||
78785919f840e8ddd06573def57eb587cc77661e7d0Jacob Bramley                  ((immediate >> kWRegSize) == 0xffffffff));
7884a102baf640077d6794c0b33bb976f94b86c532barmvixl      immediate &= kWRegMask;
7894a102baf640077d6794c0b33bb976f94b86c532barmvixl    }
7904a102baf640077d6794c0b33bb976f94b86c532barmvixl
79188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(rd.Is64Bits() || IsUint32(immediate));
7924a102baf640077d6794c0b33bb976f94b86c532barmvixl
793ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Special cases for all set or all clear immediates.
794ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if (immediate == 0) {
795ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      switch (op) {
796ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case AND:
797ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          Mov(rd, 0);
798ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          return;
7996e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl        case ORR:
8006e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl          VIXL_FALLTHROUGH();
801ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case EOR:
802ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          Mov(rd, rn);
803ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          return;
8046e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl        case ANDS:
8056e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl          VIXL_FALLTHROUGH();
806ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case BICS:
807ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          break;
808ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        default:
809b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl          VIXL_UNREACHABLE();
810ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      }
81185919f840e8ddd06573def57eb587cc77661e7d0Jacob Bramley    } else if ((rd.Is64Bits() && (immediate == UINT64_C(0xffffffffffffffff))) ||
81285919f840e8ddd06573def57eb587cc77661e7d0Jacob Bramley               (rd.Is32Bits() && (immediate == UINT64_C(0x00000000ffffffff)))) {
813ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      switch (op) {
814ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case AND:
815ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          Mov(rd, rn);
816ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          return;
817ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case ORR:
818ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          Mov(rd, immediate);
819ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          return;
820ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case EOR:
821ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          Mvn(rd, rn);
822ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          return;
8236e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl        case ANDS:
8246e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl          VIXL_FALLTHROUGH();
825ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        case BICS:
826ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl          break;
827ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        default:
828b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl          VIXL_UNREACHABLE();
829ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      }
830ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
831ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
832ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    unsigned n, imm_s, imm_r;
833ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
834ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // Immediate can be encoded in the instruction.
835ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
836ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    } else {
837ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // Immediate can't be encoded: synthesize using move immediate.
838b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      Register temp = temps.AcquireSameSizeAs(rn);
8394a102baf640077d6794c0b33bb976f94b86c532barmvixl      Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
8404a102baf640077d6794c0b33bb976f94b86c532barmvixl
841ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      if (rd.Is(sp)) {
842ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        // If rd is the stack pointer we cannot use it as the destination
843ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        // register so we use the temp register as an intermediate again.
8444a102baf640077d6794c0b33bb976f94b86c532barmvixl        Logical(temp, rn, imm_operand, op);
845ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl        Mov(sp, temp);
846ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      } else {
8474a102baf640077d6794c0b33bb976f94b86c532barmvixl        Logical(rd, rn, imm_operand, op);
848ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      }
849ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
850ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (operand.IsExtendedRegister()) {
85188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());
852ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Add/sub extended supports shift <= 4. We want to support exactly the
853ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // same modes here.
85488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetShiftAmount() <= 4);
85588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(
85688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        operand.GetRegister().Is64Bits() ||
85788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));
858b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
85988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    temps.Exclude(operand.GetRegister());
860b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
8610f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    EmitExtendShift(temp,
86288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetRegister(),
86388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetExtend(),
86488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetShiftAmount());
865ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Logical(rd, rn, Operand(temp), op);
866ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
867ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // The operand can be encoded in the instruction.
868b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    VIXL_ASSERT(operand.IsShiftedRegister());
869ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Logical(rd, rn, operand, op);
870ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
871ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
872ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
873ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
874f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Mov(const Register& rd,
875f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         const Operand& operand,
876f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         DiscardMoveMode discard_mode) {
877b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
878c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // The worst case for size is mov immediate with up to 4 instructions.
879c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
880c68cb64496485710cdb5b8480f8fee287058c93farmvixl
881ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (operand.IsImmediate()) {
882ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Call the macro assembler for generic immediates.
88388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Mov(rd, operand.GetImmediate());
88488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  } else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {
885ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Emit a shift instruction if moving a shifted register. This operation
886ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // could also be achieved using an orr instruction (like orn used by Mvn),
887ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // but using a shift instruction makes the disassembly clearer.
88888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    EmitShift(rd,
88988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetRegister(),
89088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetShift(),
89188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetShiftAmount());
892ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (operand.IsExtendedRegister()) {
893ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Emit an extend instruction if moving an extended register. This handles
894ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // extend with post-shift operations, too.
8950f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    EmitExtendShift(rd,
89688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetRegister(),
89788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetExtend(),
89888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetShiftAmount());
899ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
9001c78c34397f2c08c012733cc661076e8bd029eabAlexandre Rames    Mov(rd, operand.GetRegister(), discard_mode);
901ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
902ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
903ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
904ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
9055289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {
90688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(IsUint16(imm));
9075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  int byte1 = (imm & 0xff);
9085289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  int byte2 = ((imm >> 8) & 0xff);
9095289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (byte1 == byte2) {
9105289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);
9115289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (byte1 == 0) {
9125289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, byte2, LSL, 8);
9135289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (byte2 == 0) {
9145289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, byte1);
9155289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (byte1 == 0xff) {
9165289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    mvni(vd, ~byte2 & 0xff, LSL, 8);
9175289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (byte2 == 0xff) {
9185289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    mvni(vd, ~byte1 & 0xff);
9195289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
9205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    UseScratchRegisterScope temps(this);
9215289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Register temp = temps.AcquireW();
9225289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movz(temp, imm);
9235289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    dup(vd, temp);
9245289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9255289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
9265289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9275289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9285289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {
92988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(IsUint32(imm));
9305289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9315289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  uint8_t bytes[sizeof(imm)];
9325289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  memcpy(bytes, &imm, sizeof(imm));
9335289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9345289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // All bytes are either 0x00 or 0xff.
9355289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  {
9365289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bool all0orff = true;
9375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    for (int i = 0; i < 4; ++i) {
9385289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      if ((bytes[i] != 0) && (bytes[i] != 0xff)) {
9395289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        all0orff = false;
9405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        break;
9415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      }
9425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
9435289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9445289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (all0orff == true) {
9455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));
9465289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      return;
9475289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
9485289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9495289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9505289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Of the 4 bytes, only one byte is non-zero.
9515289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  for (int i = 0; i < 4; i++) {
9525289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if ((imm & (0xff << (i * 8))) == imm) {
9535289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      movi(vd, bytes[i], LSL, i * 8);
9545289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      return;
9555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
9565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Of the 4 bytes, only one byte is not 0xff.
9595289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  for (int i = 0; i < 4; i++) {
9605289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    uint32_t mask = ~(0xff << (i * 8));
9615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if ((imm & mask) == mask) {
9625289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);
9635289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      return;
9645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
9655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9665289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Immediate is of the form 0x00MMFFFF.
9685289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if ((imm & 0xff00ffff) == 0x0000ffff) {
9695289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, bytes[2], MSL, 16);
9705289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
9715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9735289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Immediate is of the form 0x0000MMFF.
9745289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if ((imm & 0xffff00ff) == 0x000000ff) {
9755289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, bytes[1], MSL, 8);
9765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
9775289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9795289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Immediate is of the form 0xFFMM0000.
9805289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if ((imm & 0xff00ffff) == 0xff000000) {
9815289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    mvni(vd, ~bytes[2] & 0xff, MSL, 16);
9825289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
9835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9845289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Immediate is of the form 0xFFFFMM00.
9855289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if ((imm & 0xffff00ff) == 0xffff0000) {
9865289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    mvni(vd, ~bytes[1] & 0xff, MSL, 8);
9875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
9885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Top and bottom 16-bits are equal.
9915289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {
9925289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);
9935289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
9945289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
9955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
9965289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Default case.
9975289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  {
9985289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    UseScratchRegisterScope temps(this);
9995289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Register temp = temps.AcquireW();
10005289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Mov(temp, imm);
10015289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    dup(vd, temp);
10025289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
10035289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
10045289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10055289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10065289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
10075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // All bytes are either 0x00 or 0xff.
10085289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  {
10095289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    bool all0orff = true;
10105289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    for (int i = 0; i < 8; ++i) {
10115289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      int byteval = (imm >> (i * 8)) & 0xff;
10125289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      if (byteval != 0 && byteval != 0xff) {
10135289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        all0orff = false;
10145289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        break;
10155289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      }
10165289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
10175289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (all0orff == true) {
10185289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      movi(vd, imm);
10195289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      return;
10205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
10215289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
10225289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10235289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Top and bottom 32-bits are equal.
10245289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {
10255289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);
10265289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    return;
10275289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
10285289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10295289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // Default case.
10305289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  {
10315289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    UseScratchRegisterScope temps(this);
10325289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Register temp = temps.AcquireX();
10335289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Mov(temp, imm);
10345289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (vd.Is1D()) {
10355289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      mov(vd.D(), 0, temp);
10365289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else {
10375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      dup(vd.V2D(), temp);
10385289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
10395289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
10405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
10415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10425289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10435289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Movi(const VRegister& vd,
10445289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                          uint64_t imm,
10455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                          Shift shift,
10465289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                          int shift_amount) {
10475289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(allow_macro_instructions_);
10485289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  MacroEmissionCheckScope guard(this);
10495289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (shift_amount != 0 || shift != LSL) {
10505289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, imm, shift, shift_amount);
10515289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (vd.Is8B() || vd.Is16B()) {
10525289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    // 8-bit immediate.
105388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(IsUint8(imm));
10545289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    movi(vd, imm);
10555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (vd.Is4H() || vd.Is8H()) {
10565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    // 16-bit immediate.
10575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Movi16bitHelper(vd, imm);
10585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else if (vd.Is2S() || vd.Is4S()) {
10595289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    // 32-bit immediate.
10605289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Movi32bitHelper(vd, imm);
10615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
10625289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    // 64-bit immediate.
10635289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Movi64bitHelper(vd, imm);
10645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
10655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
10665289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10680f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) {
10695289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // TODO: Move 128-bit values in a more efficient way.
10705289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(vd.Is128Bits());
10715289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  UseScratchRegisterScope temps(this);
10725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Movi(vd.V2D(), lo);
10735289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Register temp = temps.AcquireX();
10745289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Mov(temp, hi);
10755289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  Ins(vd.V2D(), 1, temp);
10765289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
10775289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
10785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1079ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
1080b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1081c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // The worst case for size is mvn immediate with up to 4 instructions.
1082c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1083c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1084ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (operand.IsImmediate()) {
1085ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Call the macro assembler for generic immediates.
108688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Mvn(rd, operand.GetImmediate());
1087ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (operand.IsExtendedRegister()) {
1088b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    UseScratchRegisterScope temps(this);
108988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    temps.Exclude(operand.GetRegister());
1090b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
1091ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Emit two instructions for the extend case. This differs from Mov, as
1092ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // the extend and invert can't be achieved in one instruction.
1093b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rd);
10940f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    EmitExtendShift(temp,
109588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetRegister(),
109688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetExtend(),
109788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetShiftAmount());
1098ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    mvn(rd, Operand(temp));
1099ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1100ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Otherwise, register and shifted register cases can be handled by the
1101ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // assembler directly, using orn.
1102ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    mvn(rd, operand);
1103ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1104ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1105ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1106ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1107ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Mov(const Register& rd, uint64_t imm) {
1108b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1109330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  MoveImmediateHelper(this, rd, imm);
1110ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1111ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1112ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1113ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Ccmp(const Register& rn,
1114ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          const Operand& operand,
1115ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          StatusFlags nzcv,
1116ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          Condition cond) {
1117b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
111888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {
111988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ConditionalCompareMacro(rn, -operand.GetImmediate(), nzcv, cond, CCMN);
1120f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  } else {
1121f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
1122f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1123ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1124ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1125ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1126ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Ccmn(const Register& rn,
1127ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          const Operand& operand,
1128ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          StatusFlags nzcv,
1129ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                          Condition cond) {
1130b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
113188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {
113288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ConditionalCompareMacro(rn, -operand.GetImmediate(), nzcv, cond, CCMP);
1133f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  } else {
1134f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
1135f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1136ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1137ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1138ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1139ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::ConditionalCompareMacro(const Register& rn,
1140ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                             const Operand& operand,
1141ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                             StatusFlags nzcv,
1142ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                             Condition cond,
1143ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                             ConditionalCompareOp op) {
1144b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT((cond != al) && (cond != nv));
1145c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // The worst case for size is ccmp immediate:
1146c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
1147c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for ccmp
1148c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1149c68cb64496485710cdb5b8480f8fee287058c93farmvixl
115088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if ((operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0)) ||
115188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (operand.IsImmediate() &&
115288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois       IsImmConditionalCompare(operand.GetImmediate()))) {
1153ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // The immediate can be encoded in the instruction, or the operand is an
1154ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // unshifted register: call the assembler.
1155ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    ConditionalCompare(rn, operand, nzcv, cond, op);
1156ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1157b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    UseScratchRegisterScope temps(this);
1158ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // The operand isn't directly supported by the instruction: perform the
1159ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // operation on a temporary register.
1160b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
1161f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    Mov(temp, operand);
1162f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    ConditionalCompare(rn, temp, nzcv, cond, op);
1163f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1164f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1165f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1166f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
11670f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::CselHelper(MacroAssembler* masm,
11680f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                const Register& rd,
11690f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                Operand left,
11700f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                Operand right,
11710f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                Condition cond,
11720f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                bool* should_synthesise_left,
11730f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                bool* should_synthesise_right) {
11740f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool emit_code = (masm != NULL);
11750f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
11760f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  VIXL_ASSERT(!emit_code || masm->allow_macro_instructions_);
1177b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT((cond != al) && (cond != nv));
11780f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  VIXL_ASSERT(!rd.IsZero() && !rd.IsSP());
117988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(left.IsImmediate() || !left.GetRegister().IsSP());
118088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(right.IsImmediate() || !right.GetRegister().IsSP());
11810f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
11820f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (should_synthesise_left != NULL) *should_synthesise_left = false;
11830f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (should_synthesise_right != NULL) *should_synthesise_right = false;
11840f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
11850f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // The worst case for size occurs when the inputs are two non encodable
11860f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // constants:
11870f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  //  * up to 4 instructions to materialise the left constant
11880f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  //  * up to 4 instructions to materialise the right constant
1189c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for csel
11900f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  EmissionCheckScope guard(masm, 9 * kInstructionSize);
11910f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  UseScratchRegisterScope temps;
11920f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (masm != NULL) {
11930f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    temps.Open(masm);
11940f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
11950f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
11960f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // Try to handle cases where both inputs are immediates.
11970f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool left_is_immediate = left.IsImmediate() || left.IsZero();
11980f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool right_is_immediate = right.IsImmediate() || right.IsZero();
11990f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (left_is_immediate && right_is_immediate &&
12000f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      CselSubHelperTwoImmediates(masm,
12010f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 rd,
12020f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 left.GetEquivalentImmediate(),
12030f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 right.GetEquivalentImmediate(),
12040f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 cond,
12050f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 should_synthesise_left,
12060f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 should_synthesise_right)) {
12070f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return;
12080f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
1209c68cb64496485710cdb5b8480f8fee287058c93farmvixl
12100f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // Handle cases where one of the two inputs is -1, 0, or 1.
12110f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool left_is_small_immediate =
12120f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      left_is_immediate && ((-1 <= left.GetEquivalentImmediate()) &&
12130f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                            (left.GetEquivalentImmediate() <= 1));
12140f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool right_is_small_immediate =
12150f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      right_is_immediate && ((-1 <= right.GetEquivalentImmediate()) &&
12160f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             (right.GetEquivalentImmediate() <= 1));
12170f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (right_is_small_immediate || left_is_small_immediate) {
12180f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    bool swapped_inputs = false;
12190f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (!right_is_small_immediate) {
12200f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      std::swap(left, right);
12210f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      cond = InvertCondition(cond);
12220f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      swapped_inputs = true;
12230f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12240f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    CselSubHelperRightSmallImmediate(masm,
12250f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     &temps,
12260f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     rd,
12270f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     left,
12280f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     right,
12290f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     cond,
12300f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                     swapped_inputs ? should_synthesise_right
12310f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                    : should_synthesise_left);
12320f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return;
12330f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12340f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
12350f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // Otherwise both inputs need to be available in registers. Synthesise them
12360f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // if necessary and emit the `csel`.
12370f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (!left.IsPlainRegister()) {
12380f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) {
12390f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      Register temp = temps.AcquireSameSizeAs(rd);
12400f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->Mov(temp, left);
12410f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      left = temp;
12420f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12430f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (should_synthesise_left != NULL) *should_synthesise_left = true;
12440f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12450f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (!right.IsPlainRegister()) {
12460f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) {
12470f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      Register temp = temps.AcquireSameSizeAs(rd);
12480f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->Mov(temp, right);
12490f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      right = temp;
12500f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12510f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (should_synthesise_right != NULL) *should_synthesise_right = true;
12520f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12530f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (emit_code) {
12540f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    VIXL_ASSERT(left.IsPlainRegister() && right.IsPlainRegister());
125588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (left.GetRegister().Is(right.GetRegister())) {
125688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      masm->Mov(rd, left.GetRegister());
12570f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    } else {
125888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      masm->csel(rd, left.GetRegister(), right.GetRegister(), cond);
12590f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12600f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12610f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl}
12620f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
12630f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
12640f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlbool MacroAssembler::CselSubHelperTwoImmediates(MacroAssembler* masm,
12650f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                const Register& rd,
12660f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                int64_t left,
12670f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                int64_t right,
12680f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                Condition cond,
12690f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                bool* should_synthesise_left,
12700f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                bool* should_synthesise_right) {
12710f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool emit_code = (masm != NULL);
12720f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (should_synthesise_left != NULL) *should_synthesise_left = false;
12730f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (should_synthesise_right != NULL) *should_synthesise_right = false;
12740f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
12750f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (left == right) {
12760f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) masm->Mov(rd, left);
12770f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return true;
12780f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  } else if (left == -right) {
12790f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (should_synthesise_right != NULL) *should_synthesise_right = true;
12800f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) {
12810f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->Mov(rd, right);
12820f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->Cneg(rd, rd, cond);
12830f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12840f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return true;
12850f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12860f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
12870f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (CselSubHelperTwoOrderedImmediates(masm, rd, left, right, cond)) {
12880f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return true;
12890f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  } else {
12900f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    std::swap(left, right);
12910f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (CselSubHelperTwoOrderedImmediates(masm,
12920f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                          rd,
12930f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                          left,
12940f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                          right,
12950f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                          InvertCondition(cond))) {
12960f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      return true;
12970f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
12980f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
12990f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13000f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // TODO: Handle more situations. For example handle `csel rd, #5, #6, cond`
13010f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  // with `cinc`.
13020f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  return false;
13030f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl}
13040f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13050f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13060f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlbool MacroAssembler::CselSubHelperTwoOrderedImmediates(MacroAssembler* masm,
13070f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                       const Register& rd,
13080f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                       int64_t left,
13090f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                       int64_t right,
13100f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                                       Condition cond) {
13110f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool emit_code = (masm != NULL);
13120f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
1313dd47fed5e4cd380a8a5a3dd4ab80d8531a5e7c93Alexandre Rames  if ((left == 1) && (right == 0)) {
13140f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) masm->cset(rd, cond);
13150f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return true;
1316dd47fed5e4cd380a8a5a3dd4ab80d8531a5e7c93Alexandre Rames  } else if ((left == -1) && (right == 0)) {
1317dd47fed5e4cd380a8a5a3dd4ab80d8531a5e7c93Alexandre Rames    if (emit_code) masm->csetm(rd, cond);
13180f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    return true;
13190f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
13200f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  return false;
13210f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl}
13220f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13230f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13240f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::CselSubHelperRightSmallImmediate(
13250f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    MacroAssembler* masm,
13260f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    UseScratchRegisterScope* temps,
13270f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    const Register& rd,
13280f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    const Operand& left,
13290f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    const Operand& right,
13300f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    Condition cond,
13310f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    bool* should_synthesise_left) {
13320f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  bool emit_code = (masm != NULL);
13330f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  VIXL_ASSERT((right.IsImmediate() || right.IsZero()) &&
13340f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl              (-1 <= right.GetEquivalentImmediate()) &&
13350f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl              (right.GetEquivalentImmediate() <= 1));
13360f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  Register left_register;
13370f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl
13380f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (left.IsPlainRegister()) {
133988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    left_register = left.GetRegister();
13400f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  } else {
13410f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (emit_code) {
13420f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      left_register = temps->AcquireSameSizeAs(rd);
13430f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->Mov(left_register, left);
13440f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    }
13450f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    if (should_synthesise_left != NULL) *should_synthesise_left = true;
13460f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
13470f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  if (emit_code) {
13480f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    int64_t imm = right.GetEquivalentImmediate();
13490f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    Register zr = AppropriateZeroRegFor(rd);
1350f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    if (imm == 0) {
13510f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->csel(rd, left_register, zr, cond);
1352f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    } else if (imm == 1) {
13530f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->csinc(rd, left_register, zr, cond);
1354ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    } else {
13550f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      VIXL_ASSERT(imm == -1);
13560f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      masm->csinv(rd, left_register, zr, cond);
1357ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
1358ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1359ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1360ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1361ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1362ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Add(const Register& rd,
1363ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
13646e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                         const Operand& operand,
13656e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                         FlagsUpdate S) {
1366b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
136788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate() && (operand.GetImmediate() < 0) &&
136888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      IsImmAddSub(-operand.GetImmediate())) {
136988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddSubMacro(rd, rn, -operand.GetImmediate(), S, SUB);
1370ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
13716e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    AddSubMacro(rd, rn, operand, S, ADD);
1372f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1373f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1374f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1375f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1376f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Adds(const Register& rd,
1377f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
1378f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
13796e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  Add(rd, rn, operand, SetFlags);
1380ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1381ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1382ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1383ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Sub(const Register& rd,
1384ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
13856e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                         const Operand& operand,
13866e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                         FlagsUpdate S) {
1387b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
138888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate() && (operand.GetImmediate() < 0) &&
138988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      IsImmAddSub(-operand.GetImmediate())) {
139088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddSubMacro(rd, rn, -operand.GetImmediate(), S, ADD);
1391f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  } else {
13926e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    AddSubMacro(rd, rn, operand, S, SUB);
1393f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1394f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1395f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1396f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1397f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Subs(const Register& rd,
1398f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
1399f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
14006e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  Sub(rd, rn, operand, SetFlags);
1401ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1402ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1403ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1404ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
1405b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1406f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Adds(AppropriateZeroRegFor(rn), rn, operand);
1407ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1408ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1409ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1410ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
1411b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1412f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Subs(AppropriateZeroRegFor(rn), rn, operand);
1413ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1414ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1415ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
14160f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Fcmp(const FPRegister& fn,
14170f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          double value,
14186e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                          FPTrapFlags trap) {
1419b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1420c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // The worst case for size is:
1421c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 to materialise the constant, using literal pool if necessary
14226e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  //  * 1 instruction for fcmp{e}
1423c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1424b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  if (value != 0.0) {
1425b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    UseScratchRegisterScope temps(this);
1426b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    FPRegister tmp = temps.AcquireSameSizeAs(fn);
1427b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Fmov(tmp, value);
14286e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    FPCompareMacro(fn, tmp, trap);
1429b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else {
14306e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    FPCompareMacro(fn, value, trap);
1431b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
1432b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
1433b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
1434b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
14356e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlvoid MacroAssembler::Fcmpe(const FPRegister& fn, double value) {
14366e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  Fcmp(fn, value, EnableTrap);
14376e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl}
14386e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
14396e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
14405289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Fmov(VRegister vd, double imm) {
1441b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1442c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Floating point immediates are loaded through the literal pool.
1443c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1444c68cb64496485710cdb5b8480f8fee287058c93farmvixl
14455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {
14465289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Fmov(vd, static_cast<float>(imm));
1447b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    return;
1448b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
1449b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
14505289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(vd.Is1D() || vd.Is2D());
1451b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  if (IsImmFP64(imm)) {
14525289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    fmov(vd, imm);
1453b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else {
145488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    uint64_t rawbits = DoubleToRawbits(imm);
14555289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (vd.IsScalar()) {
14565289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      if (rawbits == 0) {
14575289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        fmov(vd, xzr);
14585289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      } else {
1459db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl        ldr(vd,
1460db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl            new Literal<double>(imm,
1461db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl                                &literal_pool_,
1462db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl                                RawLiteral::kDeletedOnPlacementByPool));
14635289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      }
14645289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else {
14655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // TODO: consider NEON support for load literal.
14665289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      Movi(vd, rawbits);
14675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
1468b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
1469b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
1470b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
1471b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
14725289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::Fmov(VRegister vd, float imm) {
1473b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1474c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Floating point immediates are loaded through the literal pool.
1475c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1476c68cb64496485710cdb5b8480f8fee287058c93farmvixl
14775289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (vd.Is1D() || vd.Is2D()) {
14785289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    Fmov(vd, static_cast<double>(imm));
1479b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    return;
1480b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
1481b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
14825289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
1483b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  if (IsImmFP32(imm)) {
14845289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    fmov(vd, imm);
1485b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else {
148688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    uint32_t rawbits = FloatToRawbits(imm);
14875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (vd.IsScalar()) {
14885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      if (rawbits == 0) {
14895289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl        fmov(vd, wzr);
14905289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      } else {
1491db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl        ldr(vd,
1492db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl            new Literal<float>(imm,
1493db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl                               &literal_pool_,
1494db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl                               RawLiteral::kDeletedOnPlacementByPool));
14955289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      }
14965289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else {
14975289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      // TODO: consider NEON support for load literal.
14985289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      Movi(vd, rawbits);
14995289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
1500b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
1501b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
1502b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
1503b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
15040f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Neg(const Register& rd, const Operand& operand) {
1505b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1506ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (operand.IsImmediate()) {
150788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Mov(rd, -operand.GetImmediate());
1508ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1509f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    Sub(rd, AppropriateZeroRegFor(rd), operand);
1510ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1511ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1512ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1513ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
15140f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Negs(const Register& rd, const Operand& operand) {
1515b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1516f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Subs(rd, AppropriateZeroRegFor(rd), operand);
1517f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1518f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1519f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
15204a102baf640077d6794c0b33bb976f94b86c532barmvixlbool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
15214a102baf640077d6794c0b33bb976f94b86c532barmvixl                                              int64_t imm) {
1522330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  return OneInstrMoveImmediateHelper(this, dst, imm);
15234a102baf640077d6794c0b33bb976f94b86c532barmvixl}
15244a102baf640077d6794c0b33bb976f94b86c532barmvixl
15254a102baf640077d6794c0b33bb976f94b86c532barmvixl
15264a102baf640077d6794c0b33bb976f94b86c532barmvixlOperand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
15274a102baf640077d6794c0b33bb976f94b86c532barmvixl                                                  int64_t imm) {
152888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int reg_size = dst.GetSizeInBits();
15294a102baf640077d6794c0b33bb976f94b86c532barmvixl
15304a102baf640077d6794c0b33bb976f94b86c532barmvixl  // Encode the immediate in a single move instruction, if possible.
15314a102baf640077d6794c0b33bb976f94b86c532barmvixl  if (TryOneInstrMoveImmediate(dst, imm)) {
15324a102baf640077d6794c0b33bb976f94b86c532barmvixl    // The move was successful; nothing to do here.
15334a102baf640077d6794c0b33bb976f94b86c532barmvixl  } else {
15344a102baf640077d6794c0b33bb976f94b86c532barmvixl    // Pre-shift the immediate to the least-significant bits of the register.
15354a102baf640077d6794c0b33bb976f94b86c532barmvixl    int shift_low = CountTrailingZeros(imm, reg_size);
15364a102baf640077d6794c0b33bb976f94b86c532barmvixl    int64_t imm_low = imm >> shift_low;
15374a102baf640077d6794c0b33bb976f94b86c532barmvixl
15384a102baf640077d6794c0b33bb976f94b86c532barmvixl    // Pre-shift the immediate to the most-significant bits of the register,
15394a102baf640077d6794c0b33bb976f94b86c532barmvixl    // inserting set bits in the least-significant bits.
15404a102baf640077d6794c0b33bb976f94b86c532barmvixl    int shift_high = CountLeadingZeros(imm, reg_size);
15415289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
15424a102baf640077d6794c0b33bb976f94b86c532barmvixl
15434a102baf640077d6794c0b33bb976f94b86c532barmvixl    if (TryOneInstrMoveImmediate(dst, imm_low)) {
15444a102baf640077d6794c0b33bb976f94b86c532barmvixl      // The new immediate has been moved into the destination's low bits:
15454a102baf640077d6794c0b33bb976f94b86c532barmvixl      // return a new leftward-shifting operand.
15464a102baf640077d6794c0b33bb976f94b86c532barmvixl      return Operand(dst, LSL, shift_low);
15474a102baf640077d6794c0b33bb976f94b86c532barmvixl    } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
15484a102baf640077d6794c0b33bb976f94b86c532barmvixl      // The new immediate has been moved into the destination's high bits:
15494a102baf640077d6794c0b33bb976f94b86c532barmvixl      // return a new rightward-shifting operand.
15504a102baf640077d6794c0b33bb976f94b86c532barmvixl      return Operand(dst, LSR, shift_high);
15514a102baf640077d6794c0b33bb976f94b86c532barmvixl    } else {
15524a102baf640077d6794c0b33bb976f94b86c532barmvixl      Mov(dst, imm);
15534a102baf640077d6794c0b33bb976f94b86c532barmvixl    }
15544a102baf640077d6794c0b33bb976f94b86c532barmvixl  }
15554a102baf640077d6794c0b33bb976f94b86c532barmvixl  return Operand(dst);
15564a102baf640077d6794c0b33bb976f94b86c532barmvixl}
15574a102baf640077d6794c0b33bb976f94b86c532barmvixl
15584a102baf640077d6794c0b33bb976f94b86c532barmvixl
15594e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Ramesvoid MacroAssembler::Move(const GenericOperand& dst,
15604e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames                          const GenericOperand& src) {
15614e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  if (dst.Equals(src)) {
15624e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    return;
15634e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  }
15644e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
15654e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  VIXL_ASSERT(dst.IsValid() && src.IsValid());
15664e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
15674e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  // The sizes of the operands must match exactly.
15684e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  VIXL_ASSERT(dst.GetSizeInBits() == src.GetSizeInBits());
1569f5348cedd702124c90fc75e75d0195e2e485c620Pierre Langlois  VIXL_ASSERT(dst.GetSizeInBits() <= kXRegSize);
1570f5348cedd702124c90fc75e75d0195e2e485c620Pierre Langlois  int operand_size = static_cast<int>(dst.GetSizeInBits());
15714e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
15724e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  if (dst.IsCPURegister() && src.IsCPURegister()) {
15734e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    CPURegister dst_reg = dst.GetCPURegister();
15744e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    CPURegister src_reg = src.GetCPURegister();
15754e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    if (dst_reg.IsRegister() && src_reg.IsRegister()) {
15764e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames      Mov(Register(dst_reg), Register(src_reg));
15774e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    } else if (dst_reg.IsVRegister() && src_reg.IsVRegister()) {
15784e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames      Fmov(VRegister(dst_reg), VRegister(src_reg));
15794e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    } else {
15804e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames      if (dst_reg.IsRegister()) {
15814e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames        Fmov(Register(dst_reg), VRegister(src_reg));
15824e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames      } else {
15834e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames        Fmov(VRegister(dst_reg), Register(src_reg));
15844e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames      }
15854e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    }
15864e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    return;
15874e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  }
15884e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
15894e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  if (dst.IsMemOperand() && src.IsMemOperand()) {
15904e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    UseScratchRegisterScope temps(this);
15914e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    CPURegister temp = temps.AcquireCPURegisterOfSize(operand_size);
15924e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    Ldr(temp, src.GetMemOperand());
15934e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    Str(temp, dst.GetMemOperand());
15944e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    return;
15954e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  }
15964e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
15974e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  if (dst.IsCPURegister()) {
15984e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    Ldr(dst.GetCPURegister(), src.GetMemOperand());
15994e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  } else {
16004e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames    Str(src.GetCPURegister(), dst.GetMemOperand());
16014e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  }
16024e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames}
16034e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
16044e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames
16055289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixlvoid MacroAssembler::ComputeAddress(const Register& dst,
16065289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl                                    const MemOperand& mem_op) {
16075289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  // We cannot handle pre-indexing or post-indexing.
160888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(mem_op.GetAddrMode() == Offset);
160988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Register base = mem_op.GetBaseRegister();
16105289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (mem_op.IsImmediateOffset()) {
161188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Add(dst, base, mem_op.GetOffset());
16125289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  } else {
16135289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    VIXL_ASSERT(mem_op.IsRegisterOffset());
161488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Register reg_offset = mem_op.GetRegisterOffset();
161588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Shift shift = mem_op.GetShift();
161688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Extend extend = mem_op.GetExtend();
16175289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    if (shift == NO_SHIFT) {
16185289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      VIXL_ASSERT(extend != NO_EXTEND);
161988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Add(dst, base, Operand(reg_offset, extend, mem_op.GetShiftAmount()));
16205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else {
16215289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      VIXL_ASSERT(extend == NO_EXTEND);
162288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Add(dst, base, Operand(reg_offset, shift, mem_op.GetShiftAmount()));
16235289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    }
16245289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  }
16255289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl}
16265289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
16275289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
1628ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::AddSubMacro(const Register& rd,
1629ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                 const Register& rn,
1630ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                 const Operand& operand,
1631ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                 FlagsUpdate S,
1632ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                 AddSubOp op) {
1633c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case is add/sub immediate:
1634c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
1635c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for add/sub
1636c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1637c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1638f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
1639f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl      (S == LeaveFlags)) {
1640f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    // The instruction would be a nop. Avoid generating useless code.
1641f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    return;
1642f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
1643f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
164488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if ((operand.IsImmediate() && !IsImmAddSub(operand.GetImmediate())) ||
16450f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      (rn.IsZero() && !operand.IsShiftedRegister()) ||
164688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {
1647b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    UseScratchRegisterScope temps(this);
1648b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
16494a102baf640077d6794c0b33bb976f94b86c532barmvixl    if (operand.IsImmediate()) {
16504a102baf640077d6794c0b33bb976f94b86c532barmvixl      Operand imm_operand =
165188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          MoveImmediateForShiftedOp(temp, operand.GetImmediate());
16524a102baf640077d6794c0b33bb976f94b86c532barmvixl      AddSub(rd, rn, imm_operand, S, op);
16534a102baf640077d6794c0b33bb976f94b86c532barmvixl    } else {
16544a102baf640077d6794c0b33bb976f94b86c532barmvixl      Mov(temp, operand);
16554a102baf640077d6794c0b33bb976f94b86c532barmvixl      AddSub(rd, rn, temp, S, op);
16564a102baf640077d6794c0b33bb976f94b86c532barmvixl    }
1657ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1658ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    AddSub(rd, rn, operand, S, op);
1659ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1660ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1661ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1662ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1663ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Adc(const Register& rd,
1664ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
1665f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         const Operand& operand) {
1666b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1667f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
1668f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1669f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1670f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1671f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Adcs(const Register& rd,
1672f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
1673f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
1674b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1675f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
1676ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1677ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1678ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1679ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Sbc(const Register& rd,
1680ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                         const Register& rn,
1681f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                         const Operand& operand) {
1682b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1683f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
1684f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1685f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1686f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1687f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixlvoid MacroAssembler::Sbcs(const Register& rd,
1688f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Register& rn,
1689f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl                          const Operand& operand) {
1690b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1691f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
1692ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1693ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1694ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
16950f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Ngc(const Register& rd, const Operand& operand) {
1696b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1697ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Register zr = AppropriateZeroRegFor(rd);
1698f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Sbc(rd, zr, operand);
1699f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl}
1700f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
1701f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
17020f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Ngcs(const Register& rd, const Operand& operand) {
1703b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1704f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Register zr = AppropriateZeroRegFor(rd);
1705f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  Sbcs(rd, zr, operand);
1706ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1707ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1708ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1709ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::AddSubWithCarryMacro(const Register& rd,
1710ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                          const Register& rn,
1711ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                          const Operand& operand,
1712ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                          FlagsUpdate S,
1713ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                          AddSubWithCarryOp op) {
171488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());
1715c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case is addc/subc immediate:
1716c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
1717c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for add/sub
1718c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1719b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  UseScratchRegisterScope temps(this);
1720ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1721ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (operand.IsImmediate() ||
172288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {
1723ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Add/sub with carry (immediate or ROR shifted register.)
1724b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
1725ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Mov(temp, operand);
1726ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    AddSubWithCarry(rd, rn, Operand(temp), S, op);
172788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  } else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {
1728ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Add/sub with carry (shifted register).
172988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());
173088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetShift() != ROR);
173188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(
173288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        IsUintN(rd.GetSizeInBits() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,
173388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                operand.GetShiftAmount()));
173488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    temps.Exclude(operand.GetRegister());
1735b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
173688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    EmitShift(temp,
173788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetRegister(),
173888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetShift(),
173988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              operand.GetShiftAmount());
1740ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    AddSubWithCarry(rd, rn, Operand(temp), S, op);
1741ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (operand.IsExtendedRegister()) {
1742ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Add/sub with carry (extended register).
174388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());
1744ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Add/sub extended supports a shift <= 4. We want to support exactly the
1745ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // same modes.
174688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(operand.GetShiftAmount() <= 4);
174788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(
174888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        operand.GetRegister().Is64Bits() ||
174988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));
175088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    temps.Exclude(operand.GetRegister());
1751b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register temp = temps.AcquireSameSizeAs(rn);
17520f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    EmitExtendShift(temp,
175388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetRegister(),
175488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetExtend(),
175588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                    operand.GetShiftAmount());
1756ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    AddSubWithCarry(rd, rn, Operand(temp), S, op);
1757ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1758ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // The addressing mode is directly supported by the instruction.
1759ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    AddSubWithCarry(rd, rn, operand, S, op);
1760ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1761ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1762ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1763ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
17640f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl#define DEFINE_FUNCTION(FN, REGTYPE, REG, OP)                          \
17650f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
17660f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    VIXL_ASSERT(allow_macro_instructions_);                            \
17670f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    LoadStoreMacro(REG, addr, OP);                                     \
17680f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
1769ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlLS_MACRO_LIST(DEFINE_FUNCTION)
1770ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl#undef DEFINE_FUNCTION
1771ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1772330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1773ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::LoadStoreMacro(const CPURegister& rt,
1774ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                    const MemOperand& addr,
1775ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                    LoadStoreOp op) {
1776c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case is ldr/str pre/post index:
1777c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for ldr/str
1778c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
1779c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction to update the base
1780c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1781c68cb64496485710cdb5b8480f8fee287058c93farmvixl
178288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int64_t offset = addr.GetOffset();
17835289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  unsigned access_size = CalcLSDataSize(op);
1784ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1785ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Check if an immediate offset fits in the immediate field of the
1786ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // appropriate instruction. If not, emit two instructions to perform
1787ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // the operation.
17885289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&
1789ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      !IsImmLSUnscaled(offset)) {
1790ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Immediate offset that can't be encoded using unsigned or unscaled
1791ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // addressing modes.
1792b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    UseScratchRegisterScope temps(this);
179388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());
179488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Mov(temp, addr.GetOffset());
179588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    LoadStore(rt, MemOperand(addr.GetBaseRegister(), temp), op);
1796ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
1797ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Post-index beyond unscaled addressing range.
179888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);
179988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));
1800ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
1801ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Pre-index beyond unscaled addressing range.
180288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));
180388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);
1804ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
1805ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Encodable in one load/store instruction.
1806ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    LoadStore(rt, addr, op);
1807ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1808ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1809ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1810ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
18110f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl#define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
18120f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  void MacroAssembler::FN(const REGTYPE REG,        \
18130f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          const REGTYPE REG2,       \
18140f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          const MemOperand& addr) { \
18150f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    VIXL_ASSERT(allow_macro_instructions_);         \
18160f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    LoadStorePairMacro(REG, REG2, addr, OP);        \
18170f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  }
1818c68cb64496485710cdb5b8480f8fee287058c93farmvixlLSPAIR_MACRO_LIST(DEFINE_FUNCTION)
1819c68cb64496485710cdb5b8480f8fee287058c93farmvixl#undef DEFINE_FUNCTION
1820c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1821c68cb64496485710cdb5b8480f8fee287058c93farmvixlvoid MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
1822c68cb64496485710cdb5b8480f8fee287058c93farmvixl                                        const CPURegister& rt2,
1823c68cb64496485710cdb5b8480f8fee287058c93farmvixl                                        const MemOperand& addr,
1824c68cb64496485710cdb5b8480f8fee287058c93farmvixl                                        LoadStorePairOp op) {
1825c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // TODO(all): Should we support register offset for load-store-pair?
1826c68cb64496485710cdb5b8480f8fee287058c93farmvixl  VIXL_ASSERT(!addr.IsRegisterOffset());
1827c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case is ldp/stp immediate:
1828c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction for ldp/stp
1829c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * up to 4 instructions to materialise the constant
1830c68cb64496485710cdb5b8480f8fee287058c93farmvixl  //  * 1 instruction to update the base
1831c68cb64496485710cdb5b8480f8fee287058c93farmvixl  MacroEmissionCheckScope guard(this);
1832c68cb64496485710cdb5b8480f8fee287058c93farmvixl
183388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int64_t offset = addr.GetOffset();
18345289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  unsigned access_size = CalcLSPairDataSize(op);
1835c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1836c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Check if the offset fits in the immediate field of the appropriate
1837c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // instruction. If not, emit two instructions to perform the operation.
18385289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  if (IsImmLSPair(offset, access_size)) {
1839c68cb64496485710cdb5b8480f8fee287058c93farmvixl    // Encodable in one load/store pair instruction.
1840c68cb64496485710cdb5b8480f8fee287058c93farmvixl    LoadStorePair(rt, rt2, addr, op);
1841c68cb64496485710cdb5b8480f8fee287058c93farmvixl  } else {
184288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Register base = addr.GetBaseRegister();
1843c68cb64496485710cdb5b8480f8fee287058c93farmvixl    if (addr.IsImmediateOffset()) {
1844c68cb64496485710cdb5b8480f8fee287058c93farmvixl      UseScratchRegisterScope temps(this);
1845c68cb64496485710cdb5b8480f8fee287058c93farmvixl      Register temp = temps.AcquireSameSizeAs(base);
1846c68cb64496485710cdb5b8480f8fee287058c93farmvixl      Add(temp, base, offset);
1847c68cb64496485710cdb5b8480f8fee287058c93farmvixl      LoadStorePair(rt, rt2, MemOperand(temp), op);
1848c68cb64496485710cdb5b8480f8fee287058c93farmvixl    } else if (addr.IsPostIndex()) {
1849c68cb64496485710cdb5b8480f8fee287058c93farmvixl      LoadStorePair(rt, rt2, MemOperand(base), op);
1850c68cb64496485710cdb5b8480f8fee287058c93farmvixl      Add(base, base, offset);
1851c68cb64496485710cdb5b8480f8fee287058c93farmvixl    } else {
1852c68cb64496485710cdb5b8480f8fee287058c93farmvixl      VIXL_ASSERT(addr.IsPreIndex());
1853c68cb64496485710cdb5b8480f8fee287058c93farmvixl      Add(base, base, offset);
1854c68cb64496485710cdb5b8480f8fee287058c93farmvixl      LoadStorePair(rt, rt2, MemOperand(base), op);
1855c68cb64496485710cdb5b8480f8fee287058c93farmvixl    }
1856c68cb64496485710cdb5b8480f8fee287058c93farmvixl  }
1857c68cb64496485710cdb5b8480f8fee287058c93farmvixl}
1858c68cb64496485710cdb5b8480f8fee287058c93farmvixl
1859330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1860330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixlvoid MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {
1861330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  MacroEmissionCheckScope guard(this);
1862330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1863330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // There are no pre- or post-index modes for prfm.
1864330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());
1865330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1866330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // The access size is implicitly 8 bytes for all prefetch operations.
18675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  unsigned size = kXRegSizeInBytesLog2;
1868330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1869330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // Check if an immediate offset fits in the immediate field of the
1870330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // appropriate instruction. If not, emit two instructions to perform
1871330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  // the operation.
187288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.GetOffset(), size) &&
187388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      !IsImmLSUnscaled(addr.GetOffset())) {
1874330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Immediate offset that can't be encoded using unsigned or unscaled
1875330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // addressing modes.
1876330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    UseScratchRegisterScope temps(this);
187788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());
187888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Mov(temp, addr.GetOffset());
187988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Prefetch(op, MemOperand(addr.GetBaseRegister(), temp));
1880330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  } else {
1881330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    // Simple register-offsets are encodable in one instruction.
1882330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl    Prefetch(op, addr);
1883330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl  }
1884330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl}
1885330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
1886330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
18870f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Push(const CPURegister& src0,
18880f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          const CPURegister& src1,
18890f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          const CPURegister& src2,
18900f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                          const CPURegister& src3) {
1891b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1892b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
1893b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(src0.IsValid());
1894ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1895ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
189688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int size = src0.GetSizeInBytes();
1897ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1898ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PrepareForPush(count, size);
1899ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PushHelper(count, size, src0, src1, src2, src3);
1900ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1901ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1902ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
19030f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Pop(const CPURegister& dst0,
19040f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                         const CPURegister& dst1,
19050f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                         const CPURegister& dst2,
19060f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                         const CPURegister& dst3) {
1907ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // It is not valid to pop into the same register more than once in one
1908ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // instruction, not even into the zero register.
1909b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
1910b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
1911b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1912b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(dst0.IsValid());
1913ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1914ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
191588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int size = dst0.GetSizeInBytes();
1916ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1917ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PrepareForPop(count, size);
1918ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PopHelper(count, size, dst0, dst1, dst2, dst3);
1919ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1920ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1921ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1922ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PushCPURegList(CPURegList registers) {
192388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));
192488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(!registers.Overlaps(*GetScratchFPRegisterList()));
1925b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
19266e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
192788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int reg_size = registers.GetRegisterSizeInBytes();
192888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  PrepareForPush(registers.GetCount(), reg_size);
19296e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
19306e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  // Bump the stack pointer and store two registers at the bottom.
193188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int size = registers.GetTotalSizeInBytes();
19326e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  const CPURegister& bottom_0 = registers.PopLowestIndex();
19336e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  const CPURegister& bottom_1 = registers.PopLowestIndex();
19346e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  if (bottom_0.IsValid() && bottom_1.IsValid()) {
19356e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));
19366e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  } else if (bottom_0.IsValid()) {
19376e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));
19386e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  }
19396e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
19406e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  int offset = 2 * reg_size;
1941ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  while (!registers.IsEmpty()) {
19426e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const CPURegister& src0 = registers.PopLowestIndex();
19436e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const CPURegister& src1 = registers.PopLowestIndex();
19446e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    if (src1.IsValid()) {
19456e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Stp(src0, src1, MemOperand(StackPointer(), offset));
19466e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    } else {
19476e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Str(src0, MemOperand(StackPointer(), offset));
19486e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    }
19496e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    offset += 2 * reg_size;
1950ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1951ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1952ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1953ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1954ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PopCPURegList(CPURegList registers) {
195588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));
195688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(!registers.Overlaps(*GetScratchFPRegisterList()));
1957b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
19586e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
195988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int reg_size = registers.GetRegisterSizeInBytes();
196088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  PrepareForPop(registers.GetCount(), reg_size);
19616e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
19626e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
196388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int size = registers.GetTotalSizeInBytes();
19646e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  const CPURegister& bottom_0 = registers.PopLowestIndex();
19656e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  const CPURegister& bottom_1 = registers.PopLowestIndex();
19666e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
19676e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  int offset = 2 * reg_size;
1968ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  while (!registers.IsEmpty()) {
1969ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    const CPURegister& dst0 = registers.PopLowestIndex();
1970ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    const CPURegister& dst1 = registers.PopLowestIndex();
19716e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    if (dst1.IsValid()) {
19726e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Ldp(dst0, dst1, MemOperand(StackPointer(), offset));
19736e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    } else {
19746e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Ldr(dst0, MemOperand(StackPointer(), offset));
19756e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    }
19766e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    offset += 2 * reg_size;
19776e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  }
19786e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
19796e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  // Load the two registers at the bottom and drop the stack pointer.
19806e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  if (bottom_0.IsValid() && bottom_1.IsValid()) {
19816e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));
19826e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  } else if (bottom_0.IsValid()) {
19836e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));
1984ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
1985ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
1986ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1987ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1988ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PushMultipleTimes(int count, Register src) {
1989b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
199088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  int size = src.GetSizeInBytes();
1991ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
1992ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PrepareForPush(count, size);
1993ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Push up to four registers at a time if possible because if the current
1994ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // stack pointer is sp and the register size is 32, registers must be pushed
1995ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // in blocks of four in order to maintain the 16-byte alignment for sp.
1996ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  while (count >= 4) {
1997ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    PushHelper(4, size, src, src, src, src);
1998ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    count -= 4;
1999ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2000ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (count >= 2) {
2001ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    PushHelper(2, size, src, src, NoReg, NoReg);
2002ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    count -= 2;
2003ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2004ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (count == 1) {
2005ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    PushHelper(1, size, src, NoReg, NoReg, NoReg);
2006ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    count -= 1;
2007ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2008b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(count == 0);
2009ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2010ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2011ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
20120f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::PushHelper(int count,
20130f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                int size,
2014ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                const CPURegister& src0,
2015ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                const CPURegister& src1,
2016ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                const CPURegister& src2,
2017ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                const CPURegister& src3) {
2018ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Ensure that we don't unintentionally modify scratch or debug registers.
2019c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case for size is 2 stp.
202007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this,
202107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           2 * kInstructionSize,
202207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           ExactAssemblyScope::kMaximumSize);
2023ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2024b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
202588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(size == src0.GetSizeInBytes());
2026ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2027ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // When pushing multiple registers, the store order is chosen such that
2028ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Push(a, b) is equivalent to Push(a) followed by Push(b).
2029ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  switch (count) {
2030ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 1:
2031b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
2032ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
2033ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2034ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 2:
2035b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(src2.IsNone() && src3.IsNone());
2036ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
2037ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2038ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 3:
2039b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(src3.IsNone());
2040ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
2041ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      str(src0, MemOperand(StackPointer(), 2 * size));
2042ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2043ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 4:
2044ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // Skip over 4 * size, then fill in the gap. This allows four W registers
2045ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // to be pushed using sp, whilst maintaining 16-byte alignment for sp at
2046ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // all times.
2047ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
2048ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      stp(src1, src0, MemOperand(StackPointer(), 2 * size));
2049ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2050ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    default:
2051b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_UNREACHABLE();
2052ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2053ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2054ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2055ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
20560f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::PopHelper(int count,
20570f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                               int size,
2058ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                               const CPURegister& dst0,
2059ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                               const CPURegister& dst1,
2060ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                               const CPURegister& dst2,
2061ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                               const CPURegister& dst3) {
2062ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Ensure that we don't unintentionally modify scratch or debug registers.
2063c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // Worst case for size is 2 ldp.
206407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this,
206507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           2 * kInstructionSize,
206607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                           ExactAssemblyScope::kMaximumSize);
2067ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2068b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
206988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(size == dst0.GetSizeInBytes());
2070ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2071ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // When popping multiple registers, the load order is chosen such that
2072ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
2073ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  switch (count) {
2074ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 1:
2075b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
2076ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
2077ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2078ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 2:
2079b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());
2080ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
2081ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2082ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 3:
2083b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(dst3.IsNone());
2084ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldr(dst2, MemOperand(StackPointer(), 2 * size));
2085ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
2086ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2087ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    case 4:
2088ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // Load the higher addresses first, then load the lower addresses and skip
2089ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // the whole block in the second instruction. This allows four W registers
2090ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // to be popped using sp, whilst maintaining 16-byte alignment for sp at
2091ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      // all times.
2092ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
2093ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
2094ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2095ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    default:
2096b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_UNREACHABLE();
2097ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2098ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2099ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2100ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2101ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PrepareForPush(int count, int size) {
2102ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (sp.Is(StackPointer())) {
2103ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // If the current stack pointer is sp, then it must be aligned to 16 bytes
2104ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // on entry and the total size of the specified registers must also be a
2105ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // multiple of 16 bytes.
2106b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    VIXL_ASSERT((count * size) % 16 == 0);
2107ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  } else {
2108ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // Even if the current stack pointer is not the system stack pointer (sp),
2109ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // the system stack pointer will still be modified in order to comply with
2110ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // ABI rules about accessing memory below the system stack pointer.
2111ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    BumpSystemStackPointer(count * size);
2112ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2113ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2114ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2115ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2116ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PrepareForPop(int count, int size) {
2117db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  USE(count, size);
2118ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (sp.Is(StackPointer())) {
2119ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // If the current stack pointer is sp, then it must be aligned to 16 bytes
2120ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // on entry and the total size of the specified registers must also be a
2121ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    // multiple of 16 bytes.
2122b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    VIXL_ASSERT((count * size) % 16 == 0);
2123ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2124ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2125ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2126ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Poke(const Register& src, const Operand& offset) {
2127b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2128ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (offset.IsImmediate()) {
212988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(offset.GetImmediate() >= 0);
2130ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2131ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2132ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Str(src, MemOperand(StackPointer(), offset));
2133ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2134ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2135ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2136ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Peek(const Register& dst, const Operand& offset) {
2137b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2138ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (offset.IsImmediate()) {
213988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(offset.GetImmediate() >= 0);
2140ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2141ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2142ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Ldr(dst, MemOperand(StackPointer(), offset));
2143ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2144ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2145ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2146ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Claim(const Operand& size) {
2147b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2148f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
2149f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  if (size.IsZero()) {
2150f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    return;
2151f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
2152f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
2153ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (size.IsImmediate()) {
215488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(size.GetImmediate() > 0);
2155ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if (sp.Is(StackPointer())) {
215688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_ASSERT((size.GetImmediate() % 16) == 0);
2157ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
2158ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2159ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2160ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (!sp.Is(StackPointer())) {
2161ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    BumpSystemStackPointer(size);
2162ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2163ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2164ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Sub(StackPointer(), StackPointer(), size);
2165ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2166ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2167ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2168ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Drop(const Operand& size) {
2169b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2170f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
2171f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  if (size.IsZero()) {
2172f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl    return;
2173f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl  }
2174f37fdc0b307fc66239b8b754b0465d36bc0f8aedarmvixl
2175ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (size.IsImmediate()) {
217688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(size.GetImmediate() > 0);
2177ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if (sp.Is(StackPointer())) {
217888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_ASSERT((size.GetImmediate() % 16) == 0);
2179ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
2180ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2181ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2182ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Add(StackPointer(), StackPointer(), size);
2183ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2184ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2185ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2186ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PushCalleeSavedRegisters() {
2187ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Ensure that the macro-assembler doesn't use any scratch registers.
2188c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // 10 stp will be emitted.
2189c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // TODO(all): Should we use GetCalleeSaved and SavedFP.
219007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, 10 * kInstructionSize);
2191ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2192ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // This method must not be called unless the current stack pointer is sp.
2193b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(sp.Is(StackPointer()));
2194ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2195db6443499376478f5281607a3923e6ffc4c8d8ecarmvixl  MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);
2196ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2197ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x29, x30, tos);
2198ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x27, x28, tos);
2199ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x25, x26, tos);
2200ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x23, x24, tos);
2201ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x21, x22, tos);
2202ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  stp(x19, x20, tos);
22035799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
22045799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  stp(d14, d15, tos);
22055799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  stp(d12, d13, tos);
22065799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  stp(d10, d11, tos);
22075799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  stp(d8, d9, tos);
2208ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2209ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2210ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2211ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::PopCalleeSavedRegisters() {
2212ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Ensure that the macro-assembler doesn't use any scratch registers.
2213c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // 10 ldp will be emitted.
2214c68cb64496485710cdb5b8480f8fee287058c93farmvixl  // TODO(all): Should we use GetCalleeSaved and SavedFP.
221507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, 10 * kInstructionSize);
2216ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2217ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // This method must not be called unless the current stack pointer is sp.
2218b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(sp.Is(StackPointer()));
2219ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2220ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);
2221ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
22225799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  ldp(d8, d9, tos);
22235799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  ldp(d10, d11, tos);
22245799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  ldp(d12, d13, tos);
22255799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  ldp(d14, d15, tos);
22265799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
2227ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x19, x20, tos);
2228ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x21, x22, tos);
2229ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x23, x24, tos);
2230ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x25, x26, tos);
2231ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x27, x28, tos);
2232ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  ldp(x29, x30, tos);
2233ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2234ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
22356e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlvoid MacroAssembler::LoadCPURegList(CPURegList registers,
22366e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                                    const MemOperand& src) {
22376e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  LoadStoreCPURegListHelper(kLoad, registers, src);
22386e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl}
22396e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22406e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlvoid MacroAssembler::StoreCPURegList(CPURegList registers,
22416e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                                     const MemOperand& dst) {
22426e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  LoadStoreCPURegListHelper(kStore, registers, dst);
22436e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl}
22446e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22456e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22466e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlvoid MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,
22476e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                                               CPURegList registers,
22486e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl                                               const MemOperand& mem) {
22496e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  // We do not handle pre-indexing or post-indexing.
22506e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));
22516e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  VIXL_ASSERT(!registers.Overlaps(tmp_list_));
22526e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  VIXL_ASSERT(!registers.Overlaps(fptmp_list_));
22536e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  VIXL_ASSERT(!registers.IncludesAliasOf(sp));
22546e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22556e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  UseScratchRegisterScope temps(this);
22566e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22570f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers, mem, &temps);
22586a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  const int reg_size = registers.GetRegisterSizeInBytes();
22596e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22606a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  VIXL_ASSERT(IsPowerOf2(reg_size));
22616a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov
22626a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  // Since we are operating on register pairs, we would like to align on double
22636a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  // the standard size; on the other hand, we don't want to insert an extra
22646a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  // operation, which will happen if the number of registers is even. Note that
22656a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  // the alignment of the base pointer is unknown here, but we assume that it
22666a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  // is more likely to be aligned.
22676a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  if (((loc.GetOffset() & (2 * reg_size - 1)) != 0) &&
22686a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov      ((registers.GetCount() % 2) != 0)) {
22696a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov    if (op == kStore) {
22706a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov      Str(registers.PopLowestIndex(), loc);
22716a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov    } else {
22726a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov      VIXL_ASSERT(op == kLoad);
22736a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov      Ldr(registers.PopLowestIndex(), loc);
22746a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov    }
22756a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov    loc.AddOffset(reg_size);
22766a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov  }
227788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  while (registers.GetCount() >= 2) {
22786e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const CPURegister& dst0 = registers.PopLowestIndex();
22796e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const CPURegister& dst1 = registers.PopLowestIndex();
22806e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    if (op == kStore) {
22816e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Stp(dst0, dst1, loc);
22826e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    } else {
22836e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      VIXL_ASSERT(op == kLoad);
22846e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Ldp(dst0, dst1, loc);
22856e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    }
22866a46bf3b4e9ec6010133ee160dffa66f5dd4027aAnton Kirilov    loc.AddOffset(2 * reg_size);
22876e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  }
22886e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  if (!registers.IsEmpty()) {
22896e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    if (op == kStore) {
22906e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Str(registers.PopLowestIndex(), loc);
22916e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    } else {
22926e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      VIXL_ASSERT(op == kLoad);
22936e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Ldr(registers.PopLowestIndex(), loc);
22946e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    }
22956e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  }
22966e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl}
22976e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
22986e2c8275d5f34a531fe1eef7a7aa877601be8558armvixlMemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(
22996e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const CPURegList& registers,
23006e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    const MemOperand& mem,
23016e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    UseScratchRegisterScope* scratch_scope) {
23026e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  // If necessary, pre-compute the base address for the accesses.
23036e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  if (mem.IsRegisterOffset()) {
23046e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    Register reg_base = scratch_scope->AcquireX();
23056e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    ComputeAddress(reg_base, mem);
23066e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    return MemOperand(reg_base);
23076e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
23086e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  } else if (mem.IsImmediateOffset()) {
230988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int reg_size = registers.GetRegisterSizeInBytes();
231088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int total_size = registers.GetTotalSizeInBytes();
231188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int64_t min_offset = mem.GetOffset();
231288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int64_t max_offset =
231388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        mem.GetOffset() + std::max(0, total_size - 2 * reg_size);
231488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if ((registers.GetCount() >= 2) &&
23156e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl        (!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||
23166e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl         !Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {
23176e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      Register reg_base = scratch_scope->AcquireX();
23186e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      ComputeAddress(reg_base, mem);
23196e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl      return MemOperand(reg_base);
23206e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl    }
23216e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  }
23226e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
23236e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl  return mem;
23246e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl}
23256e2c8275d5f34a531fe1eef7a7aa877601be8558armvixl
2326ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::BumpSystemStackPointer(const Operand& space) {
2327b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!sp.Is(StackPointer()));
2328ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // TODO: Several callers rely on this not using scratch registers, so we use
2329ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // the assembler directly here. However, this means that large immediate
2330ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // values of 'space' cannot be handled.
233107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, kInstructionSize);
2332ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  sub(sp, StackPointer(), space);
2333ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2334ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2335ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
23365289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl// TODO(all): Fix printf for NEON registers, and resolve whether we should be
23375289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl// using FPRegister or VRegister here.
23385289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl
2339ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// This is the main Printf implementation. All callee-saved registers are
2340ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl// preserved, but NZCV and the caller-saved registers may be clobbered.
23410f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::PrintfNoPreserve(const char* format,
2342ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                      const CPURegister& arg0,
2343ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                      const CPURegister& arg1,
2344ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                      const CPURegister& arg2,
2345ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl                                      const CPURegister& arg3) {
2346ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // We cannot handle a caller-saved stack pointer. It doesn't make much sense
2347ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // in most cases anyway, so this restriction shouldn't be too serious.
2348b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));
2349b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
23505799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // The provided arguments, and their proper PCS registers.
23515799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
23525799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  CPURegister pcs[kPrintfMaxArgCount];
23535799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
23545799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  int arg_count = kPrintfMaxArgCount;
23555799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
23565799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // The PCS varargs registers for printf. Note that x0 is used for the printf
23575799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // format string.
23585799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  static const CPURegList kPCSVarargs =
23595799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);
23605799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  static const CPURegList kPCSVarargsFP =
23615289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);
23625799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
23635799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // We can use caller-saved registers as scratch values, except for the
23645799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // arguments and the PCS registers where they might need to go.
2365b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  UseScratchRegisterScope temps(this);
23665799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  temps.Include(kCallerSaved);
23675289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  temps.Include(kCallerSavedV);
23685799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  temps.Exclude(kPCSVarargs);
23695799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  temps.Exclude(kPCSVarargsFP);
2370b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  temps.Exclude(arg0, arg1, arg2, arg3);
2371ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
23725799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // Copies of the arg lists that we can iterate through.
23735799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  CPURegList pcs_varargs = kPCSVarargs;
23745799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  CPURegList pcs_varargs_fp = kPCSVarargsFP;
23755799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
23765799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // Place the arguments. There are lots of clever tricks and optimizations we
23775799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // could use here, but Printf is a debug tool so instead we just try to keep
23785799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // it simple: Move each input that isn't already in the right place to a
23795799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // scratch register, then move everything back.
23805799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
23815799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // Work out the proper PCS register for this argument.
2382ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    if (args[i].IsRegister()) {
23835799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      pcs[i] = pcs_varargs.PopLowestIndex().X();
23845799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      // We might only need a W register here. We need to know the size of the
23855799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      // argument so we can properly encode it for the simulator call.
23865799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
23875289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    } else if (args[i].IsVRegister()) {
23885799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      // In C, floats are always cast to doubles for varargs calls.
23895799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
2390ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    } else {
23915799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      VIXL_ASSERT(args[i].IsNone());
2392ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      arg_count = i;
2393ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl      break;
2394ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
2395ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
23965799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // If the argument is already in the right place, leave it where it is.
23975799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    if (args[i].Aliases(pcs[i])) continue;
23985799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
23995799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // Otherwise, if the argument is in a PCS argument register, allocate an
24005799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // appropriate scratch register and then move it out of the way.
24015799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    if (kPCSVarargs.IncludesAliasOf(args[i]) ||
24025799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        kPCSVarargsFP.IncludesAliasOf(args[i])) {
24035799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      if (args[i].IsRegister()) {
24045799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Register old_arg = Register(args[i]);
24055799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Register new_arg = temps.AcquireSameSizeAs(old_arg);
24065799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Mov(new_arg, old_arg);
24075799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        args[i] = new_arg;
24085799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      } else {
24095799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        FPRegister old_arg = FPRegister(args[i]);
24105799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
24115799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Fmov(new_arg, old_arg);
24125799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        args[i] = new_arg;
24135799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      }
24145799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    }
2415ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2416ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
24175799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // Do a second pass to move values into their final positions and perform any
24185799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // conversions that may be required.
24195799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  for (int i = 0; i < arg_count; i++) {
242088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(pcs[i].GetType() == args[i].GetType());
24215799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    if (pcs[i].IsRegister()) {
24225799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
2423ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    } else {
24245289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl      VIXL_ASSERT(pcs[i].IsVRegister());
242588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (pcs[i].GetSizeInBits() == args[i].GetSizeInBits()) {
24265799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
24275799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      } else {
24285799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
24295799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      }
2430ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    }
2431ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2432ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2433ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Load the format string into x0, as per the procedure-call standard.
2434ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  //
2435ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // To make the code as portable as possible, the format string is encoded
2436ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // directly in the instruction stream. It might be cleaner to encode it in a
2437ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // literal pool, but since Printf is usually used for debugging, it is
2438ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // beneficial for it to be minimally dependent on other features.
24395799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  temps.Exclude(x0);
2440ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Label format_address;
2441ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  Adr(x0, &format_address);
2442ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2443ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Emit the format string directly in the instruction stream.
2444c68cb64496485710cdb5b8480f8fee287058c93farmvixl  {
24455289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    BlockPoolsScope scope(this);
2446c68cb64496485710cdb5b8480f8fee287058c93farmvixl    // Data emitted:
2447c68cb64496485710cdb5b8480f8fee287058c93farmvixl    //   branch
2448c68cb64496485710cdb5b8480f8fee287058c93farmvixl    //   strlen(format) + 1 (includes null termination)
2449c68cb64496485710cdb5b8480f8fee287058c93farmvixl    //   padding to next instruction
2450c68cb64496485710cdb5b8480f8fee287058c93farmvixl    //   unreachable
24510f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    EmissionCheckScope guard(this,
24520f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                             AlignUp(strlen(format) + 1, kInstructionSize) +
24530f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl                                 2 * kInstructionSize);
2454ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Label after_data;
2455ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    B(&after_data);
2456ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Bind(&format_address);
2457c68cb64496485710cdb5b8480f8fee287058c93farmvixl    EmitString(format);
2458ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Unreachable();
2459ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Bind(&after_data);
2460ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2461ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2462ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // We don't pass any arguments on the stack, but we still need to align the C
2463ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // stack pointer to a 16-byte boundary for PCS compliance.
2464ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  if (!sp.Is(StackPointer())) {
2465ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    Bic(sp, StackPointer(), 0xf);
2466ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2467ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2468ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Actually call printf. This part needs special handling for the simulator,
2469ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // since the system printf function will use a different instruction set and
2470ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // the procedure-call standard will not be compatible.
2471703ff06a087f67fccde24a7ffbc8a2e74a406cb1Alexandre Rames  if (generate_simulator_code_) {
247207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    ExactAssemblyScope scope(this, kPrintfLength);
2473ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl    hlt(kPrintfOpcode);
24740f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    dc32(arg_count);  // kPrintfArgCountOffset
24755799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
24765799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // Determine the argument pattern.
24775799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    uint32_t arg_pattern_list = 0;
24785799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    for (int i = 0; i < arg_count; i++) {
24795799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      uint32_t arg_pattern;
24805799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      if (pcs[i].IsRegister()) {
24815799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
24825799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      } else {
24835799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        VIXL_ASSERT(pcs[i].Is64Bits());
24845799d6c5d10729eaade85ad608109c83ed1ae63barmvixl        arg_pattern = kPrintfArgD;
24855799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      }
24865799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));
24875799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
24885799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    }
24890f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    dc32(arg_pattern_list);  // kPrintfArgPatternListOffset
2490684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl  } else {
2491684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    Register tmp = temps.AcquireX();
2492684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    Mov(tmp, reinterpret_cast<uintptr_t>(printf));
2493684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    Blr(tmp);
2494ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  }
2495ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2496ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2497ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
24980f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixlvoid MacroAssembler::Printf(const char* format,
24995799d6c5d10729eaade85ad608109c83ed1ae63barmvixl                            CPURegister arg0,
25005799d6c5d10729eaade85ad608109c83ed1ae63barmvixl                            CPURegister arg1,
25015799d6c5d10729eaade85ad608109c83ed1ae63barmvixl                            CPURegister arg2,
25025799d6c5d10729eaade85ad608109c83ed1ae63barmvixl                            CPURegister arg3) {
25035799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  // We can only print sp if it is the current stack pointer.
25045799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  if (!sp.Is(StackPointer())) {
25055799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    VIXL_ASSERT(!sp.Aliases(arg0));
25065799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    VIXL_ASSERT(!sp.Aliases(arg1));
25075799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    VIXL_ASSERT(!sp.Aliases(arg2));
25085799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    VIXL_ASSERT(!sp.Aliases(arg3));
25095799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  }
25105799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
2511b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  // Make sure that the macro assembler doesn't try to use any of our arguments
2512b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  // as scratch registers.
2513b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  UseScratchRegisterScope exclude_all(this);
2514b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  exclude_all.ExcludeAll();
2515b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2516ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // Preserve all caller-saved registers as well as NZCV.
2517ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // If sp is the stack pointer, PushCPURegList asserts that the size of each
2518ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  // list is a multiple of 16 bytes.
2519ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PushCPURegList(kCallerSaved);
25205289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  PushCPURegList(kCallerSavedV);
2521ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
25220f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  {
25230f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl    UseScratchRegisterScope temps(this);
2524b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    // We can use caller-saved registers as scratch values (except for argN).
25255799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    temps.Include(kCallerSaved);
25265289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl    temps.Include(kCallerSavedV);
2527b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    temps.Exclude(arg0, arg1, arg2, arg3);
2528b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
25295799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // If any of the arguments are the current stack pointer, allocate a new
25305799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // register for them, and adjust the value to compensate for pushing the
25315799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // caller-saved registers.
25325799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    bool arg0_sp = StackPointer().Aliases(arg0);
25335799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    bool arg1_sp = StackPointer().Aliases(arg1);
25345799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    bool arg2_sp = StackPointer().Aliases(arg2);
25355799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    bool arg3_sp = StackPointer().Aliases(arg3);
25365799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
25375799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      // Allocate a register to hold the original stack pointer value, to pass
25385799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      // to PrintfNoPreserve as an argument.
25395799d6c5d10729eaade85ad608109c83ed1ae63barmvixl      Register arg_sp = temps.AcquireX();
25400f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl      Add(arg_sp,
25410f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl          StackPointer(),
254288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          kCallerSaved.GetTotalSizeInBytes() +
254388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              kCallerSavedV.GetTotalSizeInBytes());
254488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (arg0_sp) arg0 = Register(arg_sp.GetCode(), arg0.GetSizeInBits());
254588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (arg1_sp) arg1 = Register(arg_sp.GetCode(), arg1.GetSizeInBits());
254688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (arg2_sp) arg2 = Register(arg_sp.GetCode(), arg2.GetSizeInBits());
254788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (arg3_sp) arg3 = Register(arg_sp.GetCode(), arg3.GetSizeInBits());
25485799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    }
25495799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
2550b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    // Preserve NZCV.
2551b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Register tmp = temps.AcquireX();
2552b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Mrs(tmp, NZCV);
2553b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Push(tmp, xzr);
25545799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    temps.Release(tmp);
2555b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2556b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
2557b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
25585799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // Restore NZCV.
25595799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    tmp = temps.AcquireX();
2560b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Pop(xzr, tmp);
2561b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    Msr(NZCV, tmp);
25625799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    temps.Release(tmp);
2563b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
2564ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
25655289c5900fb214f2f6aa61e2a9263730dcf4cc17armvixl  PopCPURegList(kCallerSavedV);
2566ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl  PopCPURegList(kCallerSaved);
2567ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2568ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2569ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
2570b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2571ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2572703ff06a087f67fccde24a7ffbc8a2e74a406cb1Alexandre Rames  if (generate_simulator_code_) {
2573684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // The arguments to the trace pseudo instruction need to be contiguous in
2574684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // memory, so make sure we don't try to emit a literal pool.
257507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    ExactAssemblyScope scope(this, kTraceLength);
2576ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2577684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    Label start;
2578684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    bind(&start);
2579ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2580d3832965c62a8ad461b9ea9eb0994ca6b0a3da2cAlexandre Rames    // Refer to simulator-aarch64.h for a description of the marker and its
2581684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // arguments.
2582684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    hlt(kTraceOpcode);
2583ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
258488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);
2585684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    dc32(parameters);
2586ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
258788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);
2588684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    dc32(command);
2589684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl  } else {
2590684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // Emit nothing on real hardware.
2591684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    USE(parameters, command);
2592684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl  }
2593ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2594ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2595ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2596ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixlvoid MacroAssembler::Log(TraceParameters parameters) {
2597b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(allow_macro_instructions_);
2598ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2599703ff06a087f67fccde24a7ffbc8a2e74a406cb1Alexandre Rames  if (generate_simulator_code_) {
2600684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // The arguments to the log pseudo instruction need to be contiguous in
2601684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // memory, so make sure we don't try to emit a literal pool.
260207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    ExactAssemblyScope scope(this, kLogLength);
2603ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2604684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    Label start;
2605684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    bind(&start);
2606ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2607d3832965c62a8ad461b9ea9eb0994ca6b0a3da2cAlexandre Rames    // Refer to simulator-aarch64.h for a description of the marker and its
2608684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // arguments.
2609684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    hlt(kLogOpcode);
2610ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
261188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kLogParamsOffset);
2612684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    dc32(parameters);
2613684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl  } else {
2614684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    // Emit nothing on real hardware.
2615684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl    USE(parameters);
2616684cd2a7f5845539b58d0da7e012e39df49ceff0armvixl  }
2617ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}
2618ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl
2619578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2620578645f14e122d2b87d907e298cda7e7d0babf1farmvixlvoid MacroAssembler::EnableInstrumentation() {
2621b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!isprint(InstrumentStateEnable));
262207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, kInstructionSize);
2623578645f14e122d2b87d907e298cda7e7d0babf1farmvixl  movn(xzr, InstrumentStateEnable);
2624578645f14e122d2b87d907e298cda7e7d0babf1farmvixl}
2625578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2626578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2627578645f14e122d2b87d907e298cda7e7d0babf1farmvixlvoid MacroAssembler::DisableInstrumentation() {
2628b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!isprint(InstrumentStateDisable));
262907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, kInstructionSize);
2630578645f14e122d2b87d907e298cda7e7d0babf1farmvixl  movn(xzr, InstrumentStateDisable);
2631578645f14e122d2b87d907e298cda7e7d0babf1farmvixl}
2632578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2633578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2634578645f14e122d2b87d907e298cda7e7d0babf1farmvixlvoid MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
2635b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(strlen(marker_name) == 2);
2636578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2637578645f14e122d2b87d907e298cda7e7d0babf1farmvixl  // We allow only printable characters in the marker names. Unprintable
2638578645f14e122d2b87d907e298cda7e7d0babf1farmvixl  // characters are reserved for controlling features of the instrumentation.
2639b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
2640578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
264107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope scope(this, kInstructionSize);
2642578645f14e122d2b87d907e298cda7e7d0babf1farmvixl  movn(xzr, (marker_name[1] << 8) | marker_name[0]);
2643578645f14e122d2b87d907e298cda7e7d0babf1farmvixl}
2644578645f14e122d2b87d907e298cda7e7d0babf1farmvixl
2645b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2646330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixlvoid UseScratchRegisterScope::Open(MacroAssembler* masm) {
2647e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ == NULL);
26480f35e36b7f5d1d2f4d95989b418447e1a4bcc8cdarmvixl  VIXL_ASSERT(masm != NULL);
2649e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_ = masm;
2650330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2651e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  CPURegList* available = masm->GetScratchRegisterList();
2652e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  CPURegList* available_fp = masm->GetScratchFPRegisterList();
2653e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  old_available_ = available->GetList();
2654e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  old_availablefp_ = available_fp->GetList();
2655e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(available->GetType() == CPURegister::kRegister);
2656e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(available_fp->GetType() == CPURegister::kVRegister);
2657330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2658e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  parent_ = masm->GetCurrentScratchRegisterScope();
2659e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm->SetCurrentScratchRegisterScope(this);
2660330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl}
2661330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2662330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2663e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramleyvoid UseScratchRegisterScope::Close() {
2664e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  if (masm_ != NULL) {
2665e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // Ensure that scopes nest perfectly, and do not outlive their parents.
2666e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // This is a run-time check because the order of destruction of objects in
2667e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // the _same_ scope is implementation-defined, and is likely to change in
2668e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // optimised builds.
2669e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
2670e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->SetCurrentScratchRegisterScope(parent_);
2671330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2672e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->GetScratchRegisterList()->SetList(old_available_);
2673e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->GetScratchFPRegisterList()->SetList(old_availablefp_);
2674330dc7153e671968beb67f09ed2cb7b5bda334dbarmvixl
2675e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_ = NULL;
2676e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  }
2677e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley}
2678b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2679b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
26805799d6c5d10729eaade85ad608109c83ed1ae63barmvixlbool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {
2681e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  return masm_->GetScratchRegisterList()->IncludesAliasOf(reg) ||
2682e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley         masm_->GetScratchFPRegisterList()->IncludesAliasOf(reg);
26835799d6c5d10729eaade85ad608109c83ed1ae63barmvixl}
26845799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
26855799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
26864e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre RamesRegister UseScratchRegisterScope::AcquireRegisterOfSize(int size_in_bits) {
2687e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  int code = AcquireNextAvailable(masm_->GetScratchRegisterList()).GetCode();
26884e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  return Register(code, size_in_bits);
2689b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2690b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2691b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
26924e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre RamesFPRegister UseScratchRegisterScope::AcquireVRegisterOfSize(int size_in_bits) {
2693e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  int code = AcquireNextAvailable(masm_->GetScratchFPRegisterList()).GetCode();
26944e7c93cc256c7719d69279d64e4f5d09044b8b2cAlexandre Rames  return FPRegister(code, size_in_bits);
2695b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2696b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2697b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2698b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Release(const CPURegister& reg) {
2699e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
2700b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  if (reg.IsRegister()) {
2701e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    ReleaseByCode(masm_->GetScratchRegisterList(), reg.GetCode());
2702b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else if (reg.IsFPRegister()) {
2703e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    ReleaseByCode(masm_->GetScratchFPRegisterList(), reg.GetCode());
2704b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  } else {
2705b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    VIXL_ASSERT(reg.IsNone());
2706b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
2707b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2708b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2709b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
27105799d6c5d10729eaade85ad608109c83ed1ae63barmvixlvoid UseScratchRegisterScope::Include(const CPURegList& list) {
2711e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
271288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (list.GetType() == CPURegister::kRegister) {
27135799d6c5d10729eaade85ad608109c83ed1ae63barmvixl    // Make sure that neither sp nor xzr are included the list.
2714e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    IncludeByRegList(masm_->GetScratchRegisterList(),
271588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                     list.GetList() & ~(xzr.GetBit() | sp.GetBit()));
27165799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  } else {
271788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(list.GetType() == CPURegister::kVRegister);
2718e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    IncludeByRegList(masm_->GetScratchFPRegisterList(), list.GetList());
27195799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  }
27205799d6c5d10729eaade85ad608109c83ed1ae63barmvixl}
27215799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
27225799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
2723b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Include(const Register& reg1,
2724b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg2,
2725b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg3,
2726b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg4) {
2727e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
272888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RegList include =
272988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
2730b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  // Make sure that neither sp nor xzr are included the list.
273188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  include &= ~(xzr.GetBit() | sp.GetBit());
2732b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2733e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  IncludeByRegList(masm_->GetScratchRegisterList(), include);
2734b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2735b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2736b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2737b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Include(const FPRegister& reg1,
2738b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg2,
2739b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg3,
2740b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg4) {
274188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RegList include =
274288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
2743e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  IncludeByRegList(masm_->GetScratchFPRegisterList(), include);
2744b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2745b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2746b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
27475799d6c5d10729eaade85ad608109c83ed1ae63barmvixlvoid UseScratchRegisterScope::Exclude(const CPURegList& list) {
274888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (list.GetType() == CPURegister::kRegister) {
2749e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    ExcludeByRegList(masm_->GetScratchRegisterList(), list.GetList());
27505799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  } else {
275188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(list.GetType() == CPURegister::kVRegister);
2752e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    ExcludeByRegList(masm_->GetScratchFPRegisterList(), list.GetList());
27535799d6c5d10729eaade85ad608109c83ed1ae63barmvixl  }
27545799d6c5d10729eaade85ad608109c83ed1ae63barmvixl}
27555799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
27565799d6c5d10729eaade85ad608109c83ed1ae63barmvixl
2757b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Exclude(const Register& reg1,
2758b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg2,
2759b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg3,
2760b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const Register& reg4) {
276188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RegList exclude =
276288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
2763e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);
2764b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2765b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2766b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2767b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Exclude(const FPRegister& reg1,
2768b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg2,
2769b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg3,
2770b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const FPRegister& reg4) {
277188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RegList excludefp =
277288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();
2773e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchFPRegisterList(), excludefp);
2774b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2775b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2776b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2777b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::Exclude(const CPURegister& reg1,
2778b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const CPURegister& reg2,
2779b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const CPURegister& reg3,
2780b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                      const CPURegister& reg4) {
2781b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  RegList exclude = 0;
2782b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  RegList excludefp = 0;
2783b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2784b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  const CPURegister regs[] = {reg1, reg2, reg3, reg4};
2785b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2786b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
2787b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    if (regs[i].IsRegister()) {
278888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      exclude |= regs[i].GetBit();
2789b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    } else if (regs[i].IsFPRegister()) {
279088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      excludefp |= regs[i].GetBit();
2791b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    } else {
2792b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl      VIXL_ASSERT(regs[i].IsNone());
2793b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    }
2794b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  }
2795b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2796e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);
2797e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchFPRegisterList(), excludefp);
2798b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2799b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2800b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2801b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::ExcludeAll() {
2802e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchRegisterList(),
2803e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley                   masm_->GetScratchRegisterList()->GetList());
2804e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  ExcludeByRegList(masm_->GetScratchFPRegisterList(),
2805e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley                   masm_->GetScratchFPRegisterList()->GetList());
2806b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2807b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2808b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2809b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlCPURegister UseScratchRegisterScope::AcquireNextAvailable(
2810b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl    CPURegList* available) {
2811b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_CHECK(!available->IsEmpty());
2812b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  CPURegister result = available->PopLowestIndex();
2813b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  VIXL_ASSERT(!AreAliased(result, xzr, sp));
2814b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  return result;
2815b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2816b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2817b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2818b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {
2819b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl  ReleaseByRegList(available, static_cast<RegList>(1) << code);
2820b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2821b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2822b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2823b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,
2824b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                               RegList regs) {
282588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  available->SetList(available->GetList() | regs);
2826b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2827b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2828b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2829b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::IncludeByRegList(CPURegList* available,
2830b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                               RegList regs) {
283188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  available->SetList(available->GetList() | regs);
2832b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2833b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2834b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
2835b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixlvoid UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,
2836b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl                                               RegList exclude) {
283788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  available->SetList(available->GetList() & ~exclude);
2838b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl}
2839b0c8ae2a5f0abc58f67322052d39bfd47edb2892armvixl
284088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}  // namespace aarch64
2841ad96eda8944ab1c1ba55715c50d9d6f0a3ed1dcarmvixl}  // namespace vixl
2842