1b78f13911bfe6eda303e91ef215c87a165aae8aeAlexandre Rames// Copyright 2015, VIXL authors
288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// All rights reserved.
388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//
488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// Redistribution and use in source and binary forms, with or without
588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// modification, are permitted provided that the following conditions are met:
688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//
788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//   * Redistributions of source code must retain the above copyright notice,
888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//     this list of conditions and the following disclaimer.
988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//   * Redistributions in binary form must reproduce the above copyright
1088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//     notice, this list of conditions and the following disclaimer in the
1188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//     documentation and/or other materials provided with the distribution.
1288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//   * Neither the name of ARM Limited nor the names of its contributors may
1388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//     be used to endorse or promote products derived from this software
1488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//     without specific prior written permission.
1588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois//
1688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
1788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// POSSIBILITY OF SUCH DAMAGE.
2788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
28d3832965c62a8ad461b9ea9eb0994ca6b0a3da2cAlexandre Rames#include "aarch32/macro-assembler-aarch32.h"
2988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
3021d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#define STRINGIFY(x) #x
3121d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#define TOSTRING(x) STRINGIFY(x)
3221d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell
3321d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#define CONTEXT_SCOPE \
3421d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  ContextScope context(this, __FILE__ ":" TOSTRING(__LINE__))
3521d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell
3688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisnamespace vixl {
3788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisnamespace aarch32 {
3888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
39a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard// We use a subclass to access the protected `ExactAssemblyScope` constructor
40a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard// giving us control over the pools, and make the constructor private to limit
41a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard// usage to code paths emitting pools.
42a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliardclass ExactAssemblyScopeWithoutPoolsCheck : public ExactAssemblyScope {
43a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard private:
44a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler* masm,
45a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                                      size_t size,
46a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                                      SizePolicy size_policy = kExactSize)
47a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard      : ExactAssemblyScope(masm,
48a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                           size,
49a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                           size_policy,
50a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                           ExactAssemblyScope::kIgnorePools) {}
51a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard
52a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  friend class MacroAssembler;
53a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  friend class VeneerPoolManager;
54a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard};
55a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard
56a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard
5788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Open(MacroAssembler* masm) {
58e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ == NULL);
59e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm != NULL);
60e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_ = masm;
61e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley
62e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  old_available_ = masm_->GetScratchRegisterList()->GetList();
63e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  old_available_vfp_ = masm_->GetScratchVRegisterList()->GetList();
64e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley
65e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  parent_ = masm->GetCurrentScratchRegisterScope();
66e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm->SetCurrentScratchRegisterScope(this);
6788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
6888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
6988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
7088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Close() {
71e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  if (masm_ != NULL) {
72e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // Ensure that scopes nest perfectly, and do not outlive their parents.
73e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // This is a run-time check because the order of destruction of objects in
74e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // the _same_ scope is implementation-defined, and is likely to change in
75e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    // optimised builds.
76e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
77e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->SetCurrentScratchRegisterScope(parent_);
78e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley
79e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->GetScratchRegisterList()->SetList(old_available_);
80e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_->GetScratchVRegisterList()->SetList(old_available_vfp_);
81e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley
82e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley    masm_ = NULL;
8388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
8488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
8588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
8688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
8788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisbool UseScratchRegisterScope::IsAvailable(const Register& reg) const {
88e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
8988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(reg.IsValid());
90e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  return masm_->GetScratchRegisterList()->Includes(reg);
9188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
9288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
9388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
9488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisbool UseScratchRegisterScope::IsAvailable(const VRegister& reg) const {
95e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
9688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(reg.IsValid());
97e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  return masm_->GetScratchVRegisterList()->IncludesAllOf(reg);
9888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
9988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10188c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisRegister UseScratchRegisterScope::Acquire() {
102e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
103e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  Register reg = masm_->GetScratchRegisterList()->GetFirstAvailableRegister();
104e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_CHECK(reg.IsValid());
105e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchRegisterList()->Remove(reg);
10688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return reg;
10788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
10888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
11088c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisVRegister UseScratchRegisterScope::AcquireV(unsigned size_in_bits) {
11188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  switch (size_in_bits) {
11288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case kSRegSizeInBits:
11388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      return AcquireS();
11488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case kDRegSizeInBits:
11588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      return AcquireD();
11688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case kQRegSizeInBits:
11788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      return AcquireQ();
11888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    default:
11988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_UNREACHABLE();
12088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      return NoVReg;
12188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
12288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
12388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
12488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
12588c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisQRegister UseScratchRegisterScope::AcquireQ() {
126e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
127e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  QRegister reg =
128e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      masm_->GetScratchVRegisterList()->GetFirstAvailableQRegister();
129e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_CHECK(reg.IsValid());
130e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchVRegisterList()->Remove(reg);
13188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return reg;
13288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
13388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
13488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
13588c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisDRegister UseScratchRegisterScope::AcquireD() {
136e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
137e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  DRegister reg =
138e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      masm_->GetScratchVRegisterList()->GetFirstAvailableDRegister();
139e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_CHECK(reg.IsValid());
140e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchVRegisterList()->Remove(reg);
14188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return reg;
14288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
14388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
14488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
14588c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisSRegister UseScratchRegisterScope::AcquireS() {
146e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
147e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  SRegister reg =
148e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley      masm_->GetScratchVRegisterList()->GetFirstAvailableSRegister();
149e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_CHECK(reg.IsValid());
150e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchVRegisterList()->Remove(reg);
15188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return reg;
15288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
15388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
15488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
15588c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Release(const Register& reg) {
156e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
15788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(reg.IsValid());
158e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(!masm_->GetScratchRegisterList()->Includes(reg));
159e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchRegisterList()->Combine(reg);
16088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
16188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
16288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
16388c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Release(const VRegister& reg) {
164e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
16588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(reg.IsValid());
166e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(!masm_->GetScratchVRegisterList()->IncludesAliasOf(reg));
167e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchVRegisterList()->Combine(reg);
16888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
16988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
17088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
17188c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Include(const RegisterList& list) {
172e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
17388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RegisterList excluded_registers(sp, lr, pc);
17488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  uint32_t mask = list.GetList() & ~excluded_registers.GetList();
175e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  RegisterList* available = masm_->GetScratchRegisterList();
176e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  available->SetList(available->GetList() | mask);
17788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
17888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
17988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
18088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Include(const VRegisterList& list) {
181e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
182e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VRegisterList* available = masm_->GetScratchVRegisterList();
183e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  available->SetList(available->GetList() | list.GetList());
18488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
18588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
18688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
18788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Exclude(const RegisterList& list) {
188e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
189e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  RegisterList* available = masm_->GetScratchRegisterList();
190e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  available->SetList(available->GetList() & ~list.GetList());
19188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
19288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
19388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
19488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::Exclude(const VRegisterList& list) {
195e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
196e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VRegisterList* available = masm_->GetScratchVRegisterList();
197e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  available->SetList(available->GetList() & ~list.GetList());
19888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
19988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
20088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
2019ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramleyvoid UseScratchRegisterScope::Exclude(const Operand& operand) {
2029ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley  if (operand.IsImmediateShiftedRegister()) {
2039ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley    Exclude(operand.GetBaseRegister());
2049ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley  } else if (operand.IsRegisterShiftedRegister()) {
2059ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley    Exclude(operand.GetBaseRegister(), operand.GetShiftRegister());
2069ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley  } else {
2079ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley    VIXL_ASSERT(operand.IsImmediate());
2089ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley  }
2099ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley}
2109ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley
2119ee25b5df54608e45947a7f99f2c23ce61802474Jacob Bramley
21288c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid UseScratchRegisterScope::ExcludeAll() {
213e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  VIXL_ASSERT(masm_ != NULL);
214e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchRegisterList()->SetList(0);
215e8ce9f0ec7fe9484fca0c446ecc8a9d7929bea66Jacob Bramley  masm_->GetScratchVRegisterList()->SetList(0);
21688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
21788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
21888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
2197827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliardvoid VeneerPoolManager::AddLabel(Label* label) {
22015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  if (last_label_reference_offset_ != 0) {
22115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // If the pool grows faster than the instruction stream, we must adjust
22215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // the checkpoint to compensate. The veneer pool entries take 32 bits, so
22315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // this can only occur when two consecutive 16-bit instructions add veneer
22415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // pool entries.
22515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // This is typically the case for cbz and cbnz (other forward branches
22615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // have a 32 bit variant which is always used).
22715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    if (last_label_reference_offset_ + 2 * k16BitT32InstructionSizeInBytes ==
22815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        static_cast<uint32_t>(masm_->GetCursorOffset())) {
22915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      // We found two 16 bit forward branches generated one after the other.
23015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      // That means that the pool will grow by one 32-bit branch when
23115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      // the cursor offset will move forward by only one 16-bit branch.
2322272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      // Update the near checkpoint margin to manage the difference.
2332272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      near_checkpoint_margin_ +=
23415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard          k32BitT32InstructionSizeInBytes - k16BitT32InstructionSizeInBytes;
23515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    }
2367827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  }
2377827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  Label::ForwardReference& back = label->GetBackForwardRef();
23815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  VIXL_ASSERT(back.GetMaxForwardDistance() >= kCbzCbnzRange);
23915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  if (!label->IsInVeneerPool()) {
2404a30c5d68ebbc271d6d876d828ffa96db53d8d7cVincent Belliard    if (back.GetMaxForwardDistance() <= kNearLabelRange) {
24115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      near_labels_.push_back(label);
24215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      label->SetVeneerPoolManager(this, true);
24315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    } else {
24415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      far_labels_.push_back(label);
24515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      label->SetVeneerPoolManager(this, false);
24615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    }
2474a30c5d68ebbc271d6d876d828ffa96db53d8d7cVincent Belliard  } else if (back.GetMaxForwardDistance() <= kNearLabelRange) {
24815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    if (!label->IsNear()) {
24915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      far_labels_.remove(label);
25015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      near_labels_.push_back(label);
25115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      label->SetVeneerPoolManager(this, true);
25215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    }
25315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  }
25415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard
2557827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  back.SetIsBranch();
25615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  last_label_reference_offset_ = back.GetLocation();
2577827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  label->UpdateCheckpoint();
2587827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  Label::Offset tmp = label->GetCheckpoint();
25915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  if (label->IsNear()) {
26015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    if (near_checkpoint_ > tmp) near_checkpoint_ = tmp;
2612272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard    if (max_near_checkpoint_ >= tmp) {
2622272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      // This checkpoint is before some already in the near list. That means
2632272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      // that the veneer (if needed) will be emitted before some of the veneers
2642272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      // already in the list. We adjust the margin with the size of a veneer
2652272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      // branch.
2662272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      near_checkpoint_margin_ += k32BitT32InstructionSizeInBytes;
2672272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard    } else {
2682272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard      max_near_checkpoint_ = tmp;
2692272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard    }
27015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  } else {
27115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    if (far_checkpoint_ > tmp) far_checkpoint_ = tmp;
2727827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  }
27315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // Always compute the global checkpoint as, adding veneers shorten the
27415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // literals' checkpoint.
27515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  masm_->ComputeCheckpoint();
2767827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard}
2777827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard
2787827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard
2797827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliardvoid VeneerPoolManager::RemoveLabel(Label* label) {
2807827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliard  label->ClearVeneerPoolManager();
28115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  std::list<Label*>& list = label->IsNear() ? near_labels_ : far_labels_;
28215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  Label::Offset* checkpoint_reference =
28315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      label->IsNear() ? &near_checkpoint_ : &far_checkpoint_;
28415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  if (label->GetCheckpoint() == *checkpoint_reference) {
28588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // We have to compute checkpoint again.
28615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    *checkpoint_reference = Label::kMaxOffset;
28715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    for (std::list<Label*>::iterator it = list.begin(); it != list.end();) {
28888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (*it == label) {
28915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        it = list.erase(it);
29088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      } else {
29115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        *checkpoint_reference =
29215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard            std::min(*checkpoint_reference, (*it)->GetCheckpoint());
29388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ++it;
29488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
29588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
29688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    masm_->ComputeCheckpoint();
29788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  } else {
29888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // We only have to remove the label from the list.
29915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    list.remove(label);
30015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  }
30115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard}
30215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard
30315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard
30415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliardvoid VeneerPoolManager::EmitLabel(Label* label, Label::Offset emitted_target) {
305d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois  VIXL_ASSERT(!IsBlocked());
30615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // Define the veneer.
30715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  Label veneer;
30815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  masm_->Bind(&veneer);
30915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  Label::Offset label_checkpoint = Label::kMaxOffset;
31015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // Check all uses of this label.
31115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  for (Label::ForwardRefList::iterator ref = label->GetFirstForwardRef();
31215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       ref != label->GetEndForwardRef();) {
31315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    if (ref->IsBranch()) {
31415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      if (ref->GetCheckpoint() <= emitted_target) {
31515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        // Use the veneer.
31615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        masm_->EncodeLabelFor(*ref, &veneer);
31715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        ref = label->Erase(ref);
31815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      } else {
31915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        // Don't use the veneer => update checkpoint.
32015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        label_checkpoint = std::min(label_checkpoint, ref->GetCheckpoint());
32115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard        ++ref;
32288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
32315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    } else {
32415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      ++ref;
32588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
32688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
32715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  label->SetCheckpoint(label_checkpoint);
32815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  if (label->IsNear()) {
32915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    near_checkpoint_ = std::min(near_checkpoint_, label_checkpoint);
33015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  } else {
33115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    far_checkpoint_ = std::min(far_checkpoint_, label_checkpoint);
33215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  }
33315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // Generate the veneer.
334a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  ExactAssemblyScopeWithoutPoolsCheck guard(masm_,
335a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                                            kMaxInstructionSizeInBytes,
336a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                                            ExactAssemblyScope::kMaximumSize);
337a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  masm_->b(label);
338a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  masm_->AddBranchLabel(label);
33988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
34088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
34188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
3427827144797ee5ebfa0b574f45ad8ff235f919304Vincent Belliardvoid VeneerPoolManager::Emit(Label::Offset target) {
3438d191abf32edf41421f68f35585e4fce8da4d50cAlexandre Rames  VIXL_ASSERT(!IsBlocked());
34488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  // Sort labels (regarding their checkpoint) to avoid that a veneer
3452272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard  // becomes out of range.
3462272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard  near_labels_.sort(Label::CompareLabels);
34715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  far_labels_.sort(Label::CompareLabels);
34888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  // To avoid too many veneers, generate veneers which will be necessary soon.
349a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  target += static_cast<int>(GetMaxSize()) + near_checkpoint_margin_;
35088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  static const size_t kVeneerEmissionMargin = 1 * KBytes;
35188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  // To avoid too many veneers, use generated veneers for other not too far
35288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  // uses.
35388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  static const size_t kVeneerEmittedMargin = 2 * KBytes;
35488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Label::Offset emitted_target = target + kVeneerEmittedMargin;
35588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  target += kVeneerEmissionMargin;
35615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  // Reset the checkpoints. They will be computed again in the loop.
35715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  near_checkpoint_ = Label::kMaxOffset;
35815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  far_checkpoint_ = Label::kMaxOffset;
3592272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard  max_near_checkpoint_ = 0;
3602272afbda5f15c4bfb25c3c9bf95d960c9df39d6Vincent Belliard  near_checkpoint_margin_ = 0;
36115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  for (std::list<Label*>::iterator it = near_labels_.begin();
36215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       it != near_labels_.end();) {
36315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    Label* label = *it;
36415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // Move the label from the near list to the far list as it will be needed in
36515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // the far list (as the veneer will generate a far branch).
36615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // The label is pushed at the end of the list. The list remains sorted as
36715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // we use an unconditional jump which has the biggest range. However, it
36815985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // wouldn't be a problem if the items at the end of the list were not
36915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // sorted as they won't be used by this generation (their range will be
37015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    // greater than kVeneerEmittedMargin).
37115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    it = near_labels_.erase(it);
37215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    far_labels_.push_back(label);
37315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    label->SetVeneerPoolManager(this, false);
37415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    EmitLabel(label, emitted_target);
37515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  }
37615985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  for (std::list<Label*>::iterator it = far_labels_.begin();
37715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       it != far_labels_.end();) {
37888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // The labels are sorted. As soon as a veneer is not needed, we can stop.
37988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if ((*it)->GetCheckpoint() > target) {
38015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard      far_checkpoint_ = std::min(far_checkpoint_, (*it)->GetCheckpoint());
38188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
38288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
38388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // Even if we no longer have use of this label, we can keep it in the list
38488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // as the next "B" would add it back.
38515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    EmitLabel(*it, emitted_target);
38688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ++it;
38788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
38888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#ifdef VIXL_DEBUG
38915985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  for (std::list<Label*>::iterator it = near_labels_.begin();
39015985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       it != near_labels_.end();
39115985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       ++it) {
39215985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    VIXL_ASSERT((*it)->GetCheckpoint() >= near_checkpoint_);
39315985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  }
39415985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard  for (std::list<Label*>::iterator it = far_labels_.begin();
39515985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard       it != far_labels_.end();
39688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois       ++it) {
39715985a2fcc72ce0ec5e19c410b444ceec899c11fVincent Belliard    VIXL_ASSERT((*it)->GetCheckpoint() >= far_checkpoint_);
39888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
39988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#endif
40088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  masm_->ComputeCheckpoint();
40188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
40288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
40388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
40488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::PerformEnsureEmit(Label::Offset target, uint32_t size) {
405a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  EmitOption option = kBranchRequired;
406a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  Label after_pools;
407a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  Label::Offset literal_target = GetTargetForLiteralEmission();
408a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  VIXL_ASSERT(literal_target >= 0);
409a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  bool generate_veneers = target > veneer_pool_manager_.GetCheckpoint();
410a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  if (target > literal_target) {
411a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    // We will generate the literal pool. Generate all the veneers which
412a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    // would become out of range.
413a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    size_t literal_pool_size =
414a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard        literal_pool_manager_.GetLiteralPoolSize() + kMaxInstructionSizeInBytes;
415a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    VIXL_ASSERT(IsInt32(literal_pool_size));
416a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    Label::Offset veneers_target =
417a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard        AlignUp(target + static_cast<Label::Offset>(literal_pool_size), 4);
418a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    VIXL_ASSERT(veneers_target >= 0);
419a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    if (veneers_target > veneer_pool_manager_.GetCheckpoint()) {
420a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard      generate_veneers = true;
42188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
422a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  }
423fb37b5d8438252728469290fa35a779817faea00Pierre Langlois  if (!IsVeneerPoolBlocked() && generate_veneers) {
424a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    {
425a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard      ExactAssemblyScopeWithoutPoolsCheck
426a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard          guard(this,
427a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                kMaxInstructionSizeInBytes,
428a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard                ExactAssemblyScope::kMaximumSize);
429a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard      b(&after_pools);
430bd087d8fe70f7db770f37569073b8b9f77a9c372Vincent Belliard    }
431a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    veneer_pool_manager_.Emit(target);
432a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    option = kNoBranchRequired;
433a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  }
434a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  // Check if the macro-assembler's internal literal pool should be emitted
435a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  // to avoid any overflow. If we already generated the veneers, we can
436a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  // emit the pool (the branch is already done).
437fb37b5d8438252728469290fa35a779817faea00Pierre Langlois  if (!IsLiteralPoolBlocked() &&
438d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois      ((target > literal_target) || (option == kNoBranchRequired))) {
439a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard    EmitLiteralPool(option);
44088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
441a4cbc576a003da934ab58b293d9023d9b6f3077bVincent Belliard  BindHelper(&after_pools);
442919e3fe28a5024c53ede42922092bbc32e89dcb8Alexandre Rames  if (GetBuffer()->IsManaged()) {
44388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    bool grow_requested;
444919e3fe28a5024c53ede42922092bbc32e89dcb8Alexandre Rames    GetBuffer()->EnsureSpaceFor(size, &grow_requested);
44588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (grow_requested) ComputeCheckpoint();
44688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
44788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
44888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
44988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
45088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::ComputeCheckpoint() {
451bd087d8fe70f7db770f37569073b8b9f77a9c372Vincent Belliard  checkpoint_ = AlignDown(std::min(veneer_pool_manager_.GetCheckpoint(),
452bd087d8fe70f7db770f37569073b8b9f77a9c372Vincent Belliard                                   GetTargetForLiteralEmission()),
453bd087d8fe70f7db770f37569073b8b9f77a9c372Vincent Belliard                          4);
454919e3fe28a5024c53ede42922092bbc32e89dcb8Alexandre Rames  size_t buffer_size = GetBuffer()->GetCapacity();
455f5348cedd702124c90fc75e75d0195e2e485c620Pierre Langlois  VIXL_ASSERT(IsInt32(buffer_size));
456f5348cedd702124c90fc75e75d0195e2e485c620Pierre Langlois  Label::Offset buffer_checkpoint = static_cast<Label::Offset>(buffer_size);
45788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  checkpoint_ = std::min(checkpoint_, buffer_checkpoint);
45888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
45988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
46088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
4611661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Ramesvoid MacroAssembler::EmitLiteralPool(LiteralPool* const literal_pool,
4621661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames                                     EmitOption option) {
463fb37b5d8438252728469290fa35a779817faea00Pierre Langlois  VIXL_ASSERT(!IsLiteralPoolBlocked());
4641661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames  if (literal_pool->GetSize() > 0) {
4651661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames#ifdef VIXL_DEBUG
4661661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    for (LiteralPool::RawLiteralListIterator literal_it =
4671661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames             literal_pool->GetFirst();
4681661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames         literal_it != literal_pool->GetEnd();
4691661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames         literal_it++) {
4701661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      RawLiteral* literal = *literal_it;
4711661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      VIXL_ASSERT(GetCursorOffset() < literal->GetCheckpoint());
4721661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    }
4731661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames#endif
4741661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    Label after_literal;
4751661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    if (option == kBranchRequired) {
4761661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      GetBuffer()->EnsureSpaceFor(kMaxInstructionSizeInBytes);
4771661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      VIXL_ASSERT(!AllowAssembler());
4781661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      {
4791661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames        ExactAssemblyScopeWithoutPoolsCheck
4801661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames            guard(this,
4811661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames                  kMaxInstructionSizeInBytes,
4821661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames                  ExactAssemblyScope::kMaximumSize);
4831661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames        b(&after_literal);
4841661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      }
4851661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    }
4861661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    GetBuffer()->Align();
4871661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    GetBuffer()->EnsureSpaceFor(literal_pool->GetSize());
4881661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    for (LiteralPool::RawLiteralListIterator it = literal_pool->GetFirst();
4891661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames         it != literal_pool->GetEnd();
4901661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames         it++) {
4911661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      PlaceHelper(*it);
4921661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames      GetBuffer()->Align();
4931661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    }
4941661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    if (option == kBranchRequired) BindHelper(&after_literal);
4951661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames    literal_pool->Clear();
4961661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames  }
4971661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames}
4981661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames
4991661f51a172e7c3dcce6caca55b6fe6d10ebd416Alexandre Rames
50088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::HandleOutOfBoundsImmediate(Condition cond,
50188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                                Register tmp,
50288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                                uint32_t imm) {
50321376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard  if (IsUintN(16, imm)) {
504aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
5058885c17bce593f82cf90c086da242e52943c50efVincent Belliard    mov(cond, tmp, imm & 0xffff);
50621376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard    return;
50721376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard  }
50821376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard  if (IsUsingT32()) {
50921376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard    if (ImmediateT32::IsImmediateT32(~imm)) {
510aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
5118885c17bce593f82cf90c086da242e52943c50efVincent Belliard      mvn(cond, tmp, ~imm);
51221376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard      return;
51321376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard    }
51421376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard  } else {
51521376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard    if (ImmediateA32::IsImmediateA32(~imm)) {
516aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
5178885c17bce593f82cf90c086da242e52943c50efVincent Belliard      mvn(cond, tmp, ~imm);
51821376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard      return;
51921376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard    }
52021376f637832074ecd3e00f2bf9c708e5e0244b4Vincent Belliard  }
521aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
5228885c17bce593f82cf90c086da242e52943c50efVincent Belliard  mov(cond, tmp, imm & 0xffff);
5238885c17bce593f82cf90c086da242e52943c50efVincent Belliard  movt(cond, tmp, imm >> 16);
52488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
52588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
52688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
527f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliardvoid MacroAssembler::PadToMinimumBranchRange(Label* label) {
528f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard  const Label::ForwardReference* last_reference = label->GetForwardRefBack();
529f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard  if ((last_reference != NULL) && last_reference->IsUsingT32()) {
530f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard    uint32_t location = last_reference->GetLocation();
531f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard    if (location + k16BitT32InstructionSizeInBytes ==
532f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        static_cast<uint32_t>(GetCursorOffset())) {
533f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard      uint16_t* instr_ptr = buffer_.GetOffsetAddress<uint16_t*>(location);
534f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard      if ((instr_ptr[0] & kCbzCbnzMask) == kCbzCbnzValue) {
535f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        VIXL_ASSERT(!InITBlock());
536f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        // A Cbz or a Cbnz can't jump immediately after the instruction. If the
537f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        // target is immediately after the Cbz or Cbnz, we insert a nop to
538f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        // avoid that.
539f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard        EmitT32_16(k16BitT32NopOpcode);
540f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard      }
541f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard    }
542f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard  }
543f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard}
544f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard
545f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80Vincent Belliard
546f8c2284645ce651f99ba410a512279102851076eJacob BramleyMemOperand MacroAssembler::MemOperandComputationHelper(
547f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Condition cond,
548f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register scratch,
549f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register base,
550f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t offset,
551f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t extra_offset_mask) {
552f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(!AliasesAvailableScratchRegister(scratch));
553f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(!AliasesAvailableScratchRegister(base));
554f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(allow_macro_instructions_);
555f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(OutsideITBlock());
556f8c2284645ce651f99ba410a512279102851076eJacob Bramley
557f8c2284645ce651f99ba410a512279102851076eJacob Bramley  // Check for the simple pass-through case.
558f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if ((offset & extra_offset_mask) == offset) return MemOperand(base, offset);
559f8c2284645ce651f99ba410a512279102851076eJacob Bramley
560f8c2284645ce651f99ba410a512279102851076eJacob Bramley  MacroEmissionCheckScope guard(this);
561f8c2284645ce651f99ba410a512279102851076eJacob Bramley  ITScope it_scope(this, &cond);
562f8c2284645ce651f99ba410a512279102851076eJacob Bramley
563f8c2284645ce651f99ba410a512279102851076eJacob Bramley  uint32_t load_store_offset = offset & extra_offset_mask;
56452e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley  uint32_t add_offset = offset & ~extra_offset_mask;
565b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard  if ((add_offset != 0) &&
566b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard      (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
567b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    load_store_offset = 0;
568b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    add_offset = offset;
569b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard  }
57052e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
57152e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley  if (base.IsPC()) {
57252e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // Special handling for PC bases. We must read the PC in the first
57352e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // instruction (and only in that instruction), and we must also take care to
57452e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // keep the same address calculation as loads and stores. For T32, that
57552e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // means using something like ADR, which uses AlignDown(PC, 4).
57652e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
57752e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // We don't handle positive offsets from PC because the intention is not
57852e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // clear; does the user expect the offset from the current
57952e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // GetCursorOffset(), or to allow a certain amount of space after the
58052e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // instruction?
58152e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    VIXL_ASSERT((offset & 0x80000000) != 0);
58252e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    if (IsUsingT32()) {
58352e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      // T32: make the first instruction "SUB (immediate, from PC)" -- an alias
58452e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      // of ADR -- to get behaviour like loads and stores. This ADR can handle
58552e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      // at least as much offset as the load_store_offset so it can replace it.
58652e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
58752e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      uint32_t sub_pc_offset = (-offset) & 0xfff;
58852e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      load_store_offset = (offset + sub_pc_offset) & extra_offset_mask;
58952e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      add_offset = (offset + sub_pc_offset) & ~extra_offset_mask;
59052e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
59152e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      ExactAssemblyScope scope(this, k32BitT32InstructionSizeInBytes);
59252e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      sub(cond, scratch, base, sub_pc_offset);
59352e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
59452e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      if (add_offset == 0) return MemOperand(scratch, load_store_offset);
59552e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley
59652e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      // The rest of the offset can be generated in the usual way.
59752e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley      base = scratch;
59852e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    }
59952e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // A32 can use any SUB instruction, so we don't have to do anything special
60052e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley    // here except to ensure that we read the PC first.
60152e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley  }
602f8c2284645ce651f99ba410a512279102851076eJacob Bramley
60352e987eb677af65859f169b20816fa5d293c6cf0Jacob Bramley  add(cond, scratch, base, add_offset);
604f8c2284645ce651f99ba410a512279102851076eJacob Bramley  return MemOperand(scratch, load_store_offset);
605f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
606f8c2284645ce651f99ba410a512279102851076eJacob Bramley
607f8c2284645ce651f99ba410a512279102851076eJacob Bramley
608f8c2284645ce651f99ba410a512279102851076eJacob Bramleyuint32_t MacroAssembler::GetOffsetMask(InstructionType type,
609f8c2284645ce651f99ba410a512279102851076eJacob Bramley                                       AddrMode addrmode) {
610f8c2284645ce651f99ba410a512279102851076eJacob Bramley  switch (type) {
611f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdr:
612f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdrb:
613f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kStr:
614f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kStrb:
615f8c2284645ce651f99ba410a512279102851076eJacob Bramley      if (IsUsingA32() || (addrmode == Offset)) {
616f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0xfff;
617f8c2284645ce651f99ba410a512279102851076eJacob Bramley      } else {
618f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0xff;
619f8c2284645ce651f99ba410a512279102851076eJacob Bramley      }
620f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdrsb:
621f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdrh:
622f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdrsh:
623f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kStrh:
624f8c2284645ce651f99ba410a512279102851076eJacob Bramley      if (IsUsingT32() && (addrmode == Offset)) {
625f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0xfff;
626f8c2284645ce651f99ba410a512279102851076eJacob Bramley      } else {
627f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0xff;
628f8c2284645ce651f99ba410a512279102851076eJacob Bramley      }
629f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kVldr:
630f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kVstr:
631f8c2284645ce651f99ba410a512279102851076eJacob Bramley      return 0x3fc;
632f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kLdrd:
633f8c2284645ce651f99ba410a512279102851076eJacob Bramley    case kStrd:
634f8c2284645ce651f99ba410a512279102851076eJacob Bramley      if (IsUsingA32()) {
635f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0xff;
636f8c2284645ce651f99ba410a512279102851076eJacob Bramley      } else {
637f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return 0x3fc;
638f8c2284645ce651f99ba410a512279102851076eJacob Bramley      }
639f8c2284645ce651f99ba410a512279102851076eJacob Bramley    default:
640f8c2284645ce651f99ba410a512279102851076eJacob Bramley      VIXL_UNREACHABLE();
641f8c2284645ce651f99ba410a512279102851076eJacob Bramley      return 0;
642f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
643f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
644f8c2284645ce651f99ba410a512279102851076eJacob Bramley
645f8c2284645ce651f99ba410a512279102851076eJacob Bramley
64688c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRRRR(
64788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
64888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
64988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
65088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
65188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
65288c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRRRD(
65388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, uint32_t b, uint32_t c, double d) {
65488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
65588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
65688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
65788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
65888c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRRDR(
65988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, uint32_t b, double c, uint32_t d) {
66088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
66188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
66288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
66388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
66488c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRRDD(
66588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, uint32_t b, double c, double d) {
66688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
66788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
66888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
66988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
67088c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRDRR(
67188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, double b, uint32_t c, uint32_t d) {
67288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
67388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
67488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
67588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
67688c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRDRD(
67788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, double b, uint32_t c, double d) {
67888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
67988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
68088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
68188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
68288c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRDDR(
68388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, double b, double c, uint32_t d) {
68488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
68588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
68688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
68788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
68888c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineRDDD(
68988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, uint32_t a, double b, double c, double d) {
69088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
69188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
69288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
69388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
69488c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDRRR(
69588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, uint32_t b, uint32_t c, uint32_t d) {
69688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
69788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
69888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
69988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
70088c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDRRD(
70188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, uint32_t b, uint32_t c, double d) {
70288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
70388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
70488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
70588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
70688c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDRDR(
70788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, uint32_t b, double c, uint32_t d) {
70888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
70988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
71088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
71188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
71288c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDRDD(
71388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, uint32_t b, double c, double d) {
71488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
71588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
71688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
71788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
71888c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDDRR(
71988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, double b, uint32_t c, uint32_t d) {
72088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
72188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
72288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
72388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
72488c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDDRD(
72588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, double b, uint32_t c, double d) {
72688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
72788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
72888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
72988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
73088c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDDDR(
73188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, double b, double c, uint32_t d) {
73288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
73388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
73488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
73588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
73688c46b84df005638546de5e4e965bdcc31352f48Pierre LangloisHARDFLOAT void PrintfTrampolineDDDD(
73788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const char* format, double a, double b, double c, double d) {
73888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  printf(format, a, b, c, d);
73988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
74088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
74188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
74288c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Printf(const char* format,
74388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                            CPURegister reg1,
74488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                            CPURegister reg2,
74588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                            CPURegister reg3,
74688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                            CPURegister reg4) {
7474cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  // Exclude all registers from the available scratch registers, so
7484cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  // that we are able to use ip below.
7494cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  // TODO: Refactor this function to use UseScratchRegisterScope
7504cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  // for temporary registers below.
7514cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  UseScratchRegisterScope scratch(this);
7524cb13e841305b38acbd8195b1c511d59c91ec8d9Georgia Kouveli  scratch.ExcludeAll();
7531e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois  if (generate_simulator_code_) {
7541e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg4);
7551e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg3);
7561e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg2);
7571e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg1);
7581e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Push(RegisterList(r0, r1));
75925e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois    StringLiteral* format_literal =
76025e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
76125e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois    Adr(r0, format_literal);
7621e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    uint32_t args = (reg4.GetType() << 12) | (reg3.GetType() << 8) |
7631e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois                    (reg2.GetType() << 4) | reg1.GetType();
7641e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Mov(r1, args);
7651e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Hvc(kPrintfCode);
7661e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Pop(RegisterList(r0, r1));
7671e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    int size = reg4.GetRegSizeInBytes() + reg3.GetRegSizeInBytes() +
7681e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois               reg2.GetRegSizeInBytes() + reg1.GetRegSizeInBytes();
7691e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Drop(size);
77088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  } else {
7711e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Generate on a native platform => 32 bit environment.
7721e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Preserve core registers r0-r3, r12, r14
7731e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    const uint32_t saved_registers_mask =
7741e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        kCallerSavedRegistersMask | (1 << r5.GetCode());
7751e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Push(RegisterList(saved_registers_mask));
7761e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Push VFP registers.
77771bca307f4e94afdbc753e02c101b042cd218b4aPierre Langlois    Vpush(Untyped64, DRegisterList(d0, 8));
77871bca307f4e94afdbc753e02c101b042cd218b4aPierre Langlois    if (Has32DRegs()) Vpush(Untyped64, DRegisterList(d16, 16));
7791e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Search one register which has been saved and which doesn't need to be
7801e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // printed.
7811e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    RegisterList available_registers(kCallerSavedRegistersMask);
7821e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (reg1.GetType() == CPURegister::kRRegister) {
7831e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      available_registers.Remove(Register(reg1.GetCode()));
7841e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
7851e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (reg2.GetType() == CPURegister::kRRegister) {
7861e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      available_registers.Remove(Register(reg2.GetCode()));
7871e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
7881e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (reg3.GetType() == CPURegister::kRRegister) {
7891e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      available_registers.Remove(Register(reg3.GetCode()));
7901e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
7911e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (reg4.GetType() == CPURegister::kRRegister) {
7921e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      available_registers.Remove(Register(reg4.GetCode()));
7931e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
7941e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Register tmp = available_registers.GetFirstAvailableRegister();
7951e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    VIXL_ASSERT(tmp.GetType() == CPURegister::kRRegister);
7961e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Push the flags.
7971e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Mrs(tmp, APSR);
7981e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Push(tmp);
7991e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Vmrs(RegisterOrAPSR_nzcv(tmp.GetCode()), FPSCR);
8001e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Push(tmp);
8011e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Push the registers to print on the stack.
8021e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg4);
8031e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg3);
8041e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg2);
8051e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PushRegister(reg1);
8061e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    int core_count = 1;
8071e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    int vfp_count = 0;
8081e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    uint32_t printf_type = 0;
8091e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Pop the registers to print and store them into r1-r3 and/or d0-d3.
8101e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Reg4 may stay into the stack if all the register to print are core
8111e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // registers.
8121e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PreparePrintfArgument(reg1, &core_count, &vfp_count, &printf_type);
8131e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PreparePrintfArgument(reg2, &core_count, &vfp_count, &printf_type);
8141e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PreparePrintfArgument(reg3, &core_count, &vfp_count, &printf_type);
8151e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    PreparePrintfArgument(reg4, &core_count, &vfp_count, &printf_type);
8161e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Ensure that the stack is aligned on 8 bytes.
8171e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    And(r5, sp, 0x7);
8181e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (core_count == 5) {
8191e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      // One 32 bit argument (reg4) has been left on the stack =>  align the
8201e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      // stack
8211e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      // before the argument.
8221e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      Pop(r0);
8231e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      Sub(sp, sp, r5);
8241e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      Push(r0);
8251e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    } else {
8261e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      Sub(sp, sp, r5);
8271e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
8281e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Select the right trampoline depending on the arguments.
8291e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    uintptr_t address;
8301e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    switch (printf_type) {
8311e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 0:
8321e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
8331e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8341e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 1:
8351e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRR);
8361e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8371e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 2:
8381e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRR);
8391e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8401e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 3:
8411e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRR);
8421e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8431e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 4:
8441e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDR);
8451e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8461e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 5:
8471e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDR);
8481e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8491e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 6:
8501e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDR);
8511e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8521e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 7:
8531e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDR);
8541e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8551e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 8:
8561e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRD);
8571e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8581e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 9:
8591e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRD);
8601e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8611e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 10:
8621e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRD);
8631e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8641e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 11:
8651e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRD);
8661e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8671e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 12:
8681e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDD);
8691e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8701e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 13:
8711e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDD);
8721e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8731e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 14:
8741e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDD);
8751e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8761e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      case 15:
8771e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDD);
8781e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8791e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois      default:
8801e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        VIXL_UNREACHABLE();
8811e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
8821e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois        break;
8831e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    }
88425e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois    StringLiteral* format_literal =
88525e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
88625e3987b3b684df88edc8069d60b483b95587be5Pierre Langlois    Adr(r0, format_literal);
887f5348cedd702124c90fc75e75d0195e2e485c620Pierre Langlois    Mov(ip, Operand::From(address));
8881e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Blx(ip);
8891e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // If register reg4 was left on the stack => skip it.
8901e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    if (core_count == 5) Drop(kRegSizeInBytes);
8911e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Restore the stack as it was before alignment.
8921e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Add(sp, sp, r5);
8931e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Restore the flags.
8941e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Pop(tmp);
8951e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Vmsr(FPSCR, tmp);
8961e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Pop(tmp);
8971e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Msr(APSR_nzcvqg, tmp);
8981e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    // Restore the regsisters.
89971bca307f4e94afdbc753e02c101b042cd218b4aPierre Langlois    if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
90071bca307f4e94afdbc753e02c101b042cd218b4aPierre Langlois    Vpop(Untyped64, DRegisterList(d0, 8));
9011e85b7f2e8ad2bfb233de29405aade635ed207cePierre Langlois    Pop(RegisterList(saved_registers_mask));
90288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
90388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
90488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
90588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
90688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::PushRegister(CPURegister reg) {
90788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  switch (reg.GetType()) {
90888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kNoRegister:
90988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
91088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kRRegister:
91188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Push(Register(reg.GetCode()));
91288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
91388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kSRegister:
91488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Vpush(Untyped32, SRegisterList(SRegister(reg.GetCode())));
91588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
91688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kDRegister:
91788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Vpush(Untyped64, DRegisterList(DRegister(reg.GetCode())));
91888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
91988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kQRegister:
92088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_UNIMPLEMENTED();
92188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
92288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
92388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
92488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
92588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
92688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::PreparePrintfArgument(CPURegister reg,
92788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                           int* core_count,
92888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                           int* vfp_count,
92988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                           uint32_t* printf_type) {
93088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  switch (reg.GetType()) {
93188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kNoRegister:
93288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
93388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kRRegister:
93488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_ASSERT(*core_count <= 4);
93588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (*core_count < 4) Pop(Register(*core_count));
93688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      *core_count += 1;
93788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
93888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kSRegister:
93988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_ASSERT(*vfp_count < 4);
94088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      *printf_type |= 1 << (*core_count + *vfp_count - 1);
94188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Vpop(Untyped32, SRegisterList(SRegister(*vfp_count * 2)));
94288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Vcvt(F64, F32, DRegister(*vfp_count), SRegister(*vfp_count * 2));
94388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      *vfp_count += 1;
94488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
94588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kDRegister:
94688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_ASSERT(*vfp_count < 4);
94788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      *printf_type |= 1 << (*core_count + *vfp_count - 1);
94888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Vpop(Untyped64, DRegisterList(DRegister(*vfp_count)));
94988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      *vfp_count += 1;
95088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
95188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    case CPURegister::kQRegister:
95288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      VIXL_UNIMPLEMENTED();
95388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      break;
95488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
95588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
95688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
95788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
95888c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
95988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondROp instruction,
96088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
96188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rn,
96288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const Operand& operand) {
9634634a88b6db240a13adc66f26ff3437806f08aecPierre Langlois  VIXL_ASSERT((type == kMovt) || (type == kSxtb16) || (type == kTeq) ||
9644634a88b6db240a13adc66f26ff3437806f08aecPierre Langlois              (type == kUxtb16));
96530aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois
96630aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois  if (type == kMovt) {
967028fb0566f6af6d839d34ccfec754ba394510302Jacob Bramley    VIXL_ABORT_WITH_MSG("`Movt` expects a 16-bit immediate.\n");
96830aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois  }
96930aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois
97030aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois  // This delegate only supports teq with immediates.
97130aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois  CONTEXT_SCOPE;
97230aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois  if ((type == kTeq) && operand.IsImmediate()) {
97330aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    UseScratchRegisterScope temps(this);
97430aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    Register scratch = temps.Acquire();
97530aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    HandleOutOfBoundsImmediate(cond, scratch, operand.GetImmediate());
97630aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
97730aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    teq(cond, rn, scratch);
97830aaad9e13111af88c55cbbba6dc31b06e1c8d5aPierre Langlois    return;
97988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
98088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, rn, operand);
98188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
98288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
98388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
98488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
98588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondSizeROp instruction,
98688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
98788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              EncodingSize size,
98888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rn,
98988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const Operand& operand) {
99021d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
99188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(size.IsBest());
99266170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli  VIXL_ASSERT((type == kCmn) || (type == kCmp) || (type == kMov) ||
99366170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli              (type == kMovs) || (type == kMvn) || (type == kMvns) ||
99466170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli              (type == kSxtb) || (type == kSxth) || (type == kTst) ||
99566170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli              (type == kUxtb) || (type == kUxth));
99610dae1a549308bddc1931f29754d6a4459f70c9bJacob Bramley  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
99766170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli    VIXL_ASSERT((type != kMov) || (type != kMovs));
99888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    InstructionCondRROp shiftop = NULL;
99988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (operand.GetShift().GetType()) {
100088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSL:
100188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsl;
100288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
100388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSR:
100488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsr;
100588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
100688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ASR:
100788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::asr;
100888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
100988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case RRX:
101066170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
101166170ac6e8c11239700e6031dc690cc2594c0675Georgia Kouveli        VIXL_UNREACHABLE();
101288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
101388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ROR:
101488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::ror;
101588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
101688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      default:
101788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        VIXL_UNREACHABLE();
101888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
101988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (shiftop != NULL) {
102088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      UseScratchRegisterScope temps(this);
102188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register scratch = temps.Acquire();
1022aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
102388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (this->*shiftop)(cond,
102488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                       scratch,
102588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                       operand.GetBaseRegister(),
102688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                       operand.GetShiftRegister());
1027283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      (this->*instruction)(cond, size, rn, scratch);
1028283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      return;
102988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
103088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
103188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
103288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    uint32_t imm = operand.GetImmediate();
103388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (type) {
103488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kMov:
103588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kMovs:
103688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        if (!rn.IsPC()) {
103788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          // Immediate is too large, but not using PC, so handle with mov{t}.
103888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          HandleOutOfBoundsImmediate(cond, rn, imm);
103988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (type == kMovs) {
1040aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
10418885c17bce593f82cf90c086da242e52943c50efVincent Belliard            tst(cond, rn, rn);
104288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
104388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          return;
1044c12d772a9c07b86010ec7e929716a95bda2aab25Vincent Belliard        } else if (type == kMov) {
1045c12d772a9c07b86010ec7e929716a95bda2aab25Vincent Belliard          VIXL_ASSERT(IsUsingA32() || cond.Is(al));
104688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          // Immediate is too large and using PC, so handle using a temporary
104788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          // register.
104888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          UseScratchRegisterScope temps(this);
104988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          Register scratch = temps.Acquire();
1050c12d772a9c07b86010ec7e929716a95bda2aab25Vincent Belliard          HandleOutOfBoundsImmediate(al, scratch, imm);
1051aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          EnsureEmitFor(kMaxInstructionSizeInBytes);
1052283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          bx(cond, scratch);
1053283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          return;
105488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
1055c12d772a9c07b86010ec7e929716a95bda2aab25Vincent Belliard        break;
105688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kCmn:
105788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kCmp:
10582ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell        if (IsUsingA32() || !rn.IsPC()) {
105988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          UseScratchRegisterScope temps(this);
106088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          Register scratch = temps.Acquire();
106188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          HandleOutOfBoundsImmediate(cond, scratch, imm);
1062aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1063283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          (this->*instruction)(cond, size, rn, scratch);
1064283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          return;
106588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
106688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
106788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kMvn:
106888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kMvns:
1069c12d772a9c07b86010ec7e929716a95bda2aab25Vincent Belliard        if (!rn.IsPC()) {
107088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          UseScratchRegisterScope temps(this);
107188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          Register scratch = temps.Acquire();
107288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          HandleOutOfBoundsImmediate(cond, scratch, imm);
1073aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1074283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          (this->*instruction)(cond, size, rn, scratch);
1075283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          return;
107688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
107788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
10782ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell      case kTst:
10792ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell        if (IsUsingA32() || !rn.IsPC()) {
10802ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell          UseScratchRegisterScope temps(this);
10812ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell          Register scratch = temps.Acquire();
10822ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell          HandleOutOfBoundsImmediate(cond, scratch, imm);
10832ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1084283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          (this->*instruction)(cond, size, rn, scratch);
1085283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois          return;
10862ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell        }
10872ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell        break;
108888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      default:  // kSxtb, Sxth, Uxtb, Uxth
108988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
109088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
109188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
109288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, size, rn, operand);
109388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
109488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
109588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
109688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
109788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondRROp instruction,
109888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
109988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rd,
110088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rn,
110188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const Operand& operand) {
1102bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois  if ((type == kSxtab) || (type == kSxtab16) || (type == kSxtah) ||
1103bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois      (type == kUxtab) || (type == kUxtab16) || (type == kUxtah) ||
1104bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois      (type == kPkhbt) || (type == kPkhtb)) {
1105283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    UnimplementedDelegate(type);
1106283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    return;
1107bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois  }
1108bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois
1109bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois  // This delegate only handles the following instructions.
1110bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois  VIXL_ASSERT((type == kOrn) || (type == kOrns) || (type == kRsc) ||
1111bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois              (type == kRscs));
111221d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
1113d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois
1114d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  // T32 does not support register shifted register operands, emulate it.
111510dae1a549308bddc1931f29754d6a4459f70c9bJacob Bramley  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
111688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    InstructionCondRROp shiftop = NULL;
111788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (operand.GetShift().GetType()) {
111888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSL:
111988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsl;
112088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
112188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSR:
112288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsr;
112388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
112488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ASR:
112588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::asr;
112688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
112788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case RRX:
1128bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1129bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois        VIXL_UNREACHABLE();
113088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
113188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ROR:
113288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::ror;
113388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
113488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      default:
113588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        VIXL_UNREACHABLE();
113688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
113788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (shiftop != NULL) {
113888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      UseScratchRegisterScope temps(this);
113988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register rm = operand.GetBaseRegister();
114088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register rs = operand.GetShiftRegister();
1141fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard      // Try to use rd as a scratch register. We can do this if it aliases rs or
1142fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard      // rm (because we read them in the first instruction), but not rn.
114388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (!rd.Is(rn)) temps.Include(rd);
114488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register scratch = temps.Acquire();
1145aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      // TODO: The scope length was measured empirically. We should analyse the
1146aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      // worst-case size and add targetted tests.
1147aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
114888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (this->*shiftop)(cond, scratch, rm, rs);
1149283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      (this->*instruction)(cond, rd, rn, scratch);
1150283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      return;
115188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
115288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
1153d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois
1154d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  // T32 does not have a Rsc instruction, negate the lhs input and turn it into
1155d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  // an Adc. Adc and Rsc are equivalent using a bitwise NOT:
1156d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  //   adc rd, rn, operand <-> rsc rd, NOT(rn), operand
115710dae1a549308bddc1931f29754d6a4459f70c9bJacob Bramley  if (IsUsingT32() && ((type == kRsc) || (type == kRscs))) {
115888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // The RegisterShiftRegister case should have been handled above.
115988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    VIXL_ASSERT(!operand.IsRegisterShiftedRegister());
116088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    UseScratchRegisterScope temps(this);
1161fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    // Try to use rd as a scratch register. We can do this if it aliases rn
1162fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    // (because we read it in the first instruction), but not rm.
1163fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    temps.Include(rd);
1164fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    temps.Exclude(operand);
1165fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    Register negated_rn = temps.Acquire();
1166aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    {
1167aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1168aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      mvn(cond, negated_rn, rn);
1169aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    }
117088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (type == kRsc) {
1171aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1172283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      adc(cond, rd, negated_rn, operand);
1173283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      return;
117488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
1175bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois    // TODO: We shouldn't have to specify how much space the next instruction
1176bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois    // needs.
1177bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois    CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1178283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    adcs(cond, rd, negated_rn, operand);
1179283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    return;
118088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
1181d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois
11825ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard  if (operand.IsImmediate()) {
11835ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    // If the immediate can be encoded when inverted, turn Orn into Orr.
11845ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    // Otherwise rely on HandleOutOfBoundsImmediate to generate a series of
11855ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    // mov.
11865ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    int32_t imm = operand.GetSignedImmediate();
11875ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    if (((type == kOrn) || (type == kOrns)) && IsModifiedImmediate(~imm)) {
11885ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
11895ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard      switch (type) {
11905ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard        case kOrn:
11915ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          orr(cond, rd, rn, ~imm);
11925ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          return;
11935ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard        case kOrns:
11945ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          orrs(cond, rd, rn, ~imm);
11955ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          return;
11965ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard        default:
11975ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          VIXL_UNREACHABLE();
11985ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard          break;
11995ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard      }
12005ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    }
12015ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard  }
12025ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard
1203d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  // A32 does not have a Orn instruction, negate the rhs input and turn it into
1204d370ac5a89d8a5ce4f07326f5b04347465be2422Pierre Langlois  // a Orr.
120510dae1a549308bddc1931f29754d6a4459f70c9bJacob Bramley  if (IsUsingA32() && ((type == kOrn) || (type == kOrns))) {
120688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // TODO: orn r0, r1, imm -> orr r0, r1, neg(imm) if doable
120788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    //  mvn r0, r2
120888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    //  orr r0, r1, r0
120988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Register scratch;
121088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    UseScratchRegisterScope temps(this);
1211fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    // Try to use rd as a scratch register. We can do this if it aliases rs or
1212fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard    // rm (because we read them in the first instruction), but not rn.
121388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (!rd.Is(rn)) temps.Include(rd);
121488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    scratch = temps.Acquire();
1215aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    {
1216bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois      // TODO: We shouldn't have to specify how much space the next instruction
1217bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois      // needs.
1218bf9f0ca0d76df354d17c181ef2121016859f299cPierre Langlois      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1219aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      mvn(cond, scratch, operand);
1220aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    }
122188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (type == kOrns) {
1222aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1223283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      orrs(cond, rd, rn, scratch);
1224283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      return;
122588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
1226aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1227283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    orr(cond, rd, rn, scratch);
1228283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    return;
122988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
12305ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard
123188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
12325ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    UseScratchRegisterScope temps(this);
12335ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    // Allow using the destination as a scratch register if possible.
12345ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    if (!rd.Is(rn)) temps.Include(rd);
12355ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    Register scratch = temps.Acquire();
12362ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell    int32_t imm = operand.GetSignedImmediate();
12375ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    HandleOutOfBoundsImmediate(cond, scratch, imm);
12385ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
12395ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    (this->*instruction)(cond, rd, rn, scratch);
12405ddbc800588cde7e4d02f9fb7ca2f9e8c12522efVincent Belliard    return;
124188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
124288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, rd, rn, operand);
124388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
124488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
124588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
124688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
1247f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              InstructionCondSizeRL instruction,
1248f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Condition cond,
1249f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              EncodingSize size,
1250f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Register rd,
1251f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Label* label) {
1252f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT((type == kLdr) || (type == kAdr));
1253f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1254f8c2284645ce651f99ba410a512279102851076eJacob Bramley  CONTEXT_SCOPE;
1255f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(size.IsBest());
1256f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1257f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if ((type == kLdr) && label->IsBound()) {
125889d2f7702f0dc1751574bd5f9d35b5182fc65facJacob Bramley    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
1259f8c2284645ce651f99ba410a512279102851076eJacob Bramley    UseScratchRegisterScope temps(this);
1260f8c2284645ce651f99ba410a512279102851076eJacob Bramley    temps.Include(rd);
1261f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t mask = GetOffsetMask(type, Offset);
1262f8c2284645ce651f99ba410a512279102851076eJacob Bramley    ldr(rd, MemOperandComputationHelper(cond, temps.Acquire(), label, mask));
1263f8c2284645ce651f99ba410a512279102851076eJacob Bramley    return;
1264f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
1265f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1266f8c2284645ce651f99ba410a512279102851076eJacob Bramley  Assembler::Delegate(type, instruction, cond, size, rd, label);
1267f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
1268f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1269f8c2284645ce651f99ba410a512279102851076eJacob Bramley
127080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliardbool MacroAssembler::GenerateSplitInstruction(
127180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    InstructionCondSizeRROp instruction,
127280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    Condition cond,
127380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    Register rd,
127480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    Register rn,
127580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    uint32_t imm,
127680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    uint32_t mask) {
127780b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  uint32_t high = imm & ~mask;
127880b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  if (!IsModifiedImmediate(high) && !rn.IsPC()) return false;
127980b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  // If high is a modified immediate, we can perform the operation with
128080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  // only 2 instructions.
128180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  // Else, if rn is PC, we want to avoid moving PC into a temporary.
128280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  // Therefore, we also use the pattern even if the second call may
128380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  // generate 3 instructions.
128480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  uint32_t low = imm & mask;
128580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  CodeBufferCheckScope scope(this,
128680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard                             (rn.IsPC() ? 4 : 2) * kMaxInstructionSizeInBytes);
128780b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  (this->*instruction)(cond, Best, rd, rn, low);
128880b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  (this->*instruction)(cond, Best, rd, rd, high);
128980b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard  return true;
129080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard}
129180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard
129280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard
1293f8c2284645ce651f99ba410a512279102851076eJacob Bramleyvoid MacroAssembler::Delegate(InstructionType type,
129488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondSizeRROp instruction,
129588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
129688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              EncodingSize size,
129788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rd,
129888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rn,
129988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const Operand& operand) {
13002aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois  VIXL_ASSERT(
13012aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kAdc) || (type == kAdcs) || (type == kAdd) || (type == kAdds) ||
13022aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kAnd) || (type == kAnds) || (type == kAsr) || (type == kAsrs) ||
13032aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kBic) || (type == kBics) || (type == kEor) || (type == kEors) ||
13042aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kLsl) || (type == kLsls) || (type == kLsr) || (type == kLsrs) ||
13052aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kOrr) || (type == kOrrs) || (type == kRor) || (type == kRors) ||
13062aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kRsb) || (type == kRsbs) || (type == kSbc) || (type == kSbcs) ||
13072aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      (type == kSub) || (type == kSubs));
13082aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois
130921d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
131088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(size.IsBest());
131110dae1a549308bddc1931f29754d6a4459f70c9bJacob Bramley  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
131288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    InstructionCondRROp shiftop = NULL;
131388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (operand.GetShift().GetType()) {
131488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSL:
131588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsl;
131688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
131788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case LSR:
131888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::lsr;
131988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
132088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ASR:
132188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::asr;
132288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
132388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case RRX:
13242aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
13252aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        VIXL_UNREACHABLE();
132688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
132788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case ROR:
132888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        shiftop = &Assembler::ror;
132988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
133088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      default:
133188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        VIXL_UNREACHABLE();
133288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
133388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (shiftop != NULL) {
133488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      UseScratchRegisterScope temps(this);
133588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register rm = operand.GetBaseRegister();
133688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register rs = operand.GetShiftRegister();
1337fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard      // Try to use rd as a scratch register. We can do this if it aliases rs or
1338fd7f94dd378ec93adcc201d8eb9d71836948de09Vincent Belliard      // rm (because we read them in the first instruction), but not rn.
133988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (!rd.Is(rn)) temps.Include(rd);
134088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      Register scratch = temps.Acquire();
1341aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
134288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      (this->*shiftop)(cond, scratch, rm, rs);
1343283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      (this->*instruction)(cond, size, rd, rn, scratch);
1344283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois      return;
134588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
134688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
134788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
13482ec1f7562e90ebd295989c1323d59161a23dadfcMartyn Capewell    int32_t imm = operand.GetSignedImmediate();
1349e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard    if (ImmediateT32::IsImmediateT32(~imm)) {
1350e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard      if (IsUsingT32()) {
1351e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard        switch (type) {
1352e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard          case kOrr:
1353283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois            orn(cond, rd, rn, ~imm);
1354283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois            return;
1355e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard          case kOrrs:
1356283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois            orns(cond, rd, rn, ~imm);
1357283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois            return;
1358e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard          default:
1359e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard            break;
1360e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard        }
1361e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard      }
1362e2aa8941a5b41fbd9f855906b8663009eac14669Vincent Belliard    }
136388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (imm < 0) {
136488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      InstructionCondSizeRROp asmcb = NULL;
13652aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      // Add and sub are equivalent using an arithmetic negation:
13662aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      //   add rd, rn, #imm <-> sub rd, rn, - #imm
13672aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      // Add and sub with carry are equivalent using a bitwise NOT:
13682aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois      //   adc rd, rn, #imm <-> sbc rd, rn, NOT #imm
136988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      switch (type) {
137088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case kAdd:
137188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          asmcb = &Assembler::sub;
137288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          imm = -imm;
137388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
137488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case kAdds:
137588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          asmcb = &Assembler::subs;
137688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          imm = -imm;
137788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
137888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case kSub:
137988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          asmcb = &Assembler::add;
138088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          imm = -imm;
138188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
13822aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        case kSubs:
13832aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          asmcb = &Assembler::adds;
13842aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          imm = -imm;
13852aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          break;
13862aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        case kAdc:
13872aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          asmcb = &Assembler::sbc;
13882aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          imm = ~imm;
13892aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          break;
13902aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        case kAdcs:
13912aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          asmcb = &Assembler::sbcs;
13922aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          imm = ~imm;
13932aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          break;
139488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case kSbc:
139588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          asmcb = &Assembler::adc;
139688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          imm = ~imm;
139788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
13982aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois        case kSbcs:
13992aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          asmcb = &Assembler::adcs;
14002aa0afc4afb9409c97261e1dab9abc456a7551edPierre Langlois          imm = ~imm;
140188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
140288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        default:
140388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
140488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
140588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (asmcb != NULL) {
14065c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1407283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        (this->*asmcb)(cond, size, rd, rn, Operand(imm));
1408283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
140988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
141088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
141180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard
141280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // When rn is PC, only handle negative offsets. The correct way to handle
141380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // positive offsets isn't clear; does the user want the offset from the
141480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // start of the macro, or from the end (to allow a certain amount of space)?
141580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // When type is Add or Sub, imm is always positive (imm < 0 has just been
141680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // handled and imm == 0 would have been generated without the need of a
141780b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    // delegate). Therefore, only add to PC is forbidden here.
141880b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    if ((((type == kAdd) && !rn.IsPC()) || (type == kSub)) &&
141980b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        (IsUsingA32() || (!rd.IsPC() && !rn.IsPC()))) {
142080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      VIXL_ASSERT(imm > 0);
142180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      // Try to break the constant into two modified immediates.
142280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      // For T32 also try to break the constant into one imm12 and one modified
142380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      // immediate. Count the trailing zeroes and get the biggest even value.
142480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      int trailing_zeroes = CountTrailingZeros(imm) & ~1u;
142580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      uint32_t mask = ((trailing_zeroes < 4) && IsUsingT32())
142680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard                          ? 0xfff
142780b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard                          : (0xff << trailing_zeroes);
142880b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      if (GenerateSplitInstruction(instruction, cond, rd, rn, imm, mask)) {
142980b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        return;
143080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      }
143180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      InstructionCondSizeRROp asmcb = NULL;
143280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      switch (type) {
143380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        case kAdd:
143480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard          asmcb = &Assembler::sub;
143580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard          break;
143680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        case kSub:
143780b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard          asmcb = &Assembler::add;
143880b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard          break;
143980b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        default:
144080b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard          VIXL_UNREACHABLE();
144180b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      }
144280b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      if (GenerateSplitInstruction(asmcb, cond, rd, rn, -imm, mask)) {
144380b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard        return;
144480b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard      }
144580b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard    }
144680b4a1f554a92b2c4d4504265d0bac545c74c69bVincent Belliard
144788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    UseScratchRegisterScope temps(this);
144888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    // Allow using the destination as a scratch register if possible.
144988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (!rd.Is(rn)) temps.Include(rd);
14505c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley    if (rn.IsPC()) {
14515c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // If we're reading the PC, we need to do it in the first instruction,
14525c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // otherwise we'll read the wrong value. We rely on this to handle the
14535c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // long-range PC-relative MemOperands which can result from user-managed
14545c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // literals.
14555c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley
14565c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // Only handle negative offsets. The correct way to handle positive
14575c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // offsets isn't clear; does the user want the offset from the start of
14585c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // the macro, or from the end (to allow a certain amount of space)?
14595c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      bool offset_is_negative_or_zero = (imm <= 0);
14605c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      switch (type) {
14615c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kAdd:
14625c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kAdds:
14635c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          offset_is_negative_or_zero = (imm <= 0);
14645c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          break;
14655c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kSub:
14665c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kSubs:
14675c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          offset_is_negative_or_zero = (imm >= 0);
14685c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          break;
14695c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kAdc:
14705c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kAdcs:
14715c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          offset_is_negative_or_zero = (imm < 0);
14725c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          break;
14735c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kSbc:
14745c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        case kSbcs:
14755c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          offset_is_negative_or_zero = (imm > 0);
14765c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          break;
14775c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        default:
14785c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          break;
14795c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      }
14805c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      if (offset_is_negative_or_zero) {
14815c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        {
14825c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          rn = temps.Acquire();
14835c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
14845c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley          mov(cond, rn, pc);
14855c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        }
14865c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        // Recurse rather than falling through, to try to get the immediate into
14875c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        // a single instruction.
14885c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
14895c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        (this->*instruction)(cond, size, rd, rn, operand);
14905c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley        return;
14915c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      }
14925c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley    } else {
14935c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      Register scratch = temps.Acquire();
14945c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // TODO: The scope length was measured empirically. We should analyse the
14955c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      // worst-case size and add targetted tests.
14965c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
14975c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      mov(cond, scratch, operand.GetImmediate());
14985c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      (this->*instruction)(cond, size, rd, rn, scratch);
14995c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley      return;
15005c76fb48ece5cc54c3000abead7e6147ac843834Jacob Bramley    }
150188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
150288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, size, rd, rn, operand);
150388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
150488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
150588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
150688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
150788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionRL instruction,
150888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rn,
150988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Label* label) {
15105b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli  VIXL_ASSERT((type == kCbz) || (type == kCbnz));
15115b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli
151221d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
1513aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
15145b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli  if (IsUsingA32()) {
15155b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli    if (type == kCbz) {
15165b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli      VIXL_ABORT_WITH_MSG("Cbz is only available for T32.\n");
15175b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli    } else {
15185b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli      VIXL_ABORT_WITH_MSG("Cbnz is only available for T32.\n");
15195b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli    }
15205b698cc633932dee5dd94f44a42f0fdec567fe2bGeorgia Kouveli  } else if (rn.IsLow()) {
152188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (type) {
152288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kCbnz: {
152388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Label done;
15248885c17bce593f82cf90c086da242e52943c50efVincent Belliard        cbz(rn, &done);
15258885c17bce593f82cf90c086da242e52943c50efVincent Belliard        b(label);
152688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Bind(&done);
152788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
152888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
152988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case kCbz: {
153088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Label done;
15318885c17bce593f82cf90c086da242e52943c50efVincent Belliard        cbnz(rn, &done);
15328885c17bce593f82cf90c086da242e52943c50efVincent Belliard        b(label);
153388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Bind(&done);
153488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
153588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
153688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      default:
153788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
153888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
153988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
154088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, rn, label);
154188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
154288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
154388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
154488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloistemplate <typename T>
154588c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisstatic inline bool IsI64BitPattern(T imm) {
154688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
154788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (((imm & mask) != mask) && ((imm & mask) != 0)) return false;
154888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
154988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return true;
155088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
155188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
155288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
155388c46b84df005638546de5e4e965bdcc31352f48Pierre Langloistemplate <typename T>
155488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisstatic inline bool IsI8BitPattern(T imm) {
155588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  uint8_t imm8 = imm & 0xff;
155688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  for (unsigned rep = sizeof(T) - 1; rep > 0; rep--) {
155788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    imm >>= 8;
155888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if ((imm & 0xff) != imm8) return false;
155988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
156088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return true;
156188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
156288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
156388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
156488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisstatic inline bool CanBeInverted(uint32_t imm32) {
156588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  uint32_t fill8 = 0;
156688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
156788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if ((imm32 & 0xffffff00) == 0xffffff00) {
156888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    //    11111111 11111111 11111111 abcdefgh
156988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    return true;
157088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
157188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (((imm32 & 0xff) == 0) || ((imm32 & 0xff) == 0xff)) {
157288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    fill8 = imm32 & 0xff;
157388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    imm32 >>= 8;
157488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if ((imm32 >> 8) == 0xffff) {
157588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      //    11111111 11111111 abcdefgh 00000000
157688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      // or 11111111 11111111 abcdefgh 11111111
157788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      return true;
157888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
157988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if ((imm32 & 0xff) == fill8) {
158088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      imm32 >>= 8;
158188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if ((imm32 >> 8) == 0xff) {
158288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //    11111111 abcdefgh 00000000 00000000
158388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // or 11111111 abcdefgh 11111111 11111111
158488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return true;
158588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
158688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if ((fill8 == 0xff) && ((imm32 & 0xff) == 0xff)) {
158788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //    abcdefgh 11111111 11111111 11111111
158888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return true;
158988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
159088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
159188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
159288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return false;
159388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
159488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
159588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
159688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloistemplate <typename RES, typename T>
159788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisstatic inline RES replicate(T imm) {
159888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT((sizeof(RES) > sizeof(T)) &&
159988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              (((sizeof(RES) / sizeof(T)) * sizeof(T)) == sizeof(RES)));
160088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  RES res = imm;
160188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  for (unsigned i = sizeof(RES) / sizeof(T) - 1; i > 0; i--) {
160288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    res = (res << (sizeof(T) * 8)) | imm;
160388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
160488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return res;
160588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
160688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
160788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
160888c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
160988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondDtSSop instruction,
161088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
161188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DataType dt,
161288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              SRegister rd,
161388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const SOperand& operand) {
161421d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
161588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (type == kVmov) {
161688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (operand.IsImmediate() && dt.Is(F32)) {
161788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
161888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (neon_imm.CanConvert<float>()) {
161988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // movw ip, imm16
162088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // movk ip, imm16
162188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vmov s0, ip
162288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
162388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
162488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        float f = neon_imm.GetImmediate<float>();
1625aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // TODO: The scope length was measured empirically. We should analyse
1626aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // the
1627aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // worst-case size and add targetted tests.
1628aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
16298885c17bce593f82cf90c086da242e52943c50efVincent Belliard        mov(cond, scratch, FloatToRawbits(f));
1630283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vmov(cond, rd, scratch);
1631283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
163288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
163388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
163488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
163588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
163688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
163788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
163888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
163988c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
164088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondDtDDop instruction,
164188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
164288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DataType dt,
164388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DRegister rd,
164488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const DOperand& operand) {
164521d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
164688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (type == kVmov) {
164788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (operand.IsImmediate()) {
164888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
164988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      switch (dt.GetValue()) {
165088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I32:
165188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint32_t>()) {
165288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
165388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
165488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1655aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1656283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1657283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
165888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
165988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xff0000ff will translate into
166088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i64 d0, 0xff0000ffff0000ff
166188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI64BitPattern(imm)) {
1662aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1663283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1664283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
166588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
166688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xffab0000 will translate into
166788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmvn.i32 d0, 0x0054ffff
166888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (cond.Is(al) && CanBeInverted(imm)) {
1669aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1670283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmvn(I32, rd, ~imm);
1671283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
167288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
167388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
167488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
167588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I16:
167688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint16_t>()) {
167788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
167888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
167988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1680aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1681283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1682283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
168388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
168488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
168588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
168688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I64:
168788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint64_t>()) {
168888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
168988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
169088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1691aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1692283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1693283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
169488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
169588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // mov ip, lo(imm64)
169688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vdup d0, ip
169788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vdup is prefered to 'vmov d0[0]' as d0[1] does not need to be
169888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // preserved
169988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            {
170088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              UseScratchRegisterScope temps(this);
170188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              Register scratch = temps.Acquire();
1702aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              {
1703aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // TODO: The scope length was measured empirically. We should
1704aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // analyse the
1705aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // worst-case size and add targetted tests.
1706aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                CodeBufferCheckScope scope(this,
1707aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                                           2 * kMaxInstructionSizeInBytes);
1708aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1709aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              }
1710aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
17118885c17bce593f82cf90c086da242e52943c50efVincent Belliard              vdup(cond, Untyped32, rd, scratch);
171288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
171388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // mov ip, hi(imm64)
171488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov d0[1], ip
171588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            {
171688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              UseScratchRegisterScope temps(this);
171788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              Register scratch = temps.Acquire();
1718aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              {
1719aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // TODO: The scope length was measured empirically. We should
1720aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // analyse the
1721aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                // worst-case size and add targetted tests.
1722aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                CodeBufferCheckScope scope(this,
1723aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                                           2 * kMaxInstructionSizeInBytes);
1724aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1725aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              }
1726aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
17278885c17bce593f82cf90c086da242e52943c50efVincent Belliard              vmov(cond, Untyped32, DRegisterLane(rd, 1), scratch);
172888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
172988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            return;
173088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
173188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
173288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        default:
173388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
173488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
1735960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1736960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
173788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // mov ip, imm32
1738960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        // vdup.16 d0, ip
173988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
174088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
1741aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
1742960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1743aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1744aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
174588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        DataTypeValue vdup_dt = Untyped32;
174688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        switch (dt.GetValue()) {
174788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          case I16:
174888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            vdup_dt = Untyped16;
174988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            break;
175088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          case I32:
175188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            vdup_dt = Untyped32;
175288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            break;
175388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          default:
175488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            VIXL_UNREACHABLE();
175588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
1756aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1757283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vdup(cond, vdup_dt, rd, scratch);
1758283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
175988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
176088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
176188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        float f = neon_imm.GetImmediate<float>();
176288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Punt to vmov.i32
1763aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // TODO: The scope length was guessed based on the double case below. We
1764aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // should analyse the worst-case size and add targetted tests.
1765aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1766283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vmov(cond, I32, rd, FloatToRawbits(f));
1767283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
176888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
176988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
177088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Punt to vmov.i64
177188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        double d = neon_imm.GetImmediate<double>();
1772aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // TODO: The scope length was measured empirically. We should analyse
1773aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // the
1774aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        // worst-case size and add targetted tests.
1775aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1776283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vmov(cond, I64, rd, DoubleToRawbits(d));
1777283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
177888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
177988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
178088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
178188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
178288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
178388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
178488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
178588c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
178688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondDtQQop instruction,
178788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
178888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DataType dt,
178988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              QRegister rd,
179088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const QOperand& operand) {
179121d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
179288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (type == kVmov) {
179388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if (operand.IsImmediate()) {
179488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
179588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      switch (dt.GetValue()) {
179688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I32:
179788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint32_t>()) {
179888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
179988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
180088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1801aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1802283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1803283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
180488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
180588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xff0000ff will translate into
180688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i64 d0, 0xff0000ffff0000ff
180788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI64BitPattern(imm)) {
1808aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1809283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1810283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
181188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
181288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0, 0xffab0000 will translate into
181388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmvn.i32 d0, 0x0054ffff
181488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (CanBeInverted(imm)) {
1815aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1816283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmvn(cond, I32, rd, ~imm);
1817283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
181888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
181988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
182088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
182188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I16:
182288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint16_t>()) {
182388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
182488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
182588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1826aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1827283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1828283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
182988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
183088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
183188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
183288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        case I64:
183388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          if (neon_imm.CanConvert<uint64_t>()) {
183488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
183588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
183688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            if (IsI8BitPattern(imm)) {
1837aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1838283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              vmov(cond, I8, rd, imm & 0xff);
1839283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois              return;
184088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
184188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // mov ip, lo(imm64)
184288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vdup q0, ip
184388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vdup is prefered to 'vmov d0[0]' as d0[1-3] don't need to be
184488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // preserved
184588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            {
184688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              UseScratchRegisterScope temps(this);
184788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              Register scratch = temps.Acquire();
1848aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              {
1849960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell                CodeBufferCheckScope scope(this,
1850960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell                                           2 * kMaxInstructionSizeInBytes);
1851aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1852aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              }
1853aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
18548885c17bce593f82cf90c086da242e52943c50efVincent Belliard              vdup(cond, Untyped32, rd, scratch);
185588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
185688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // mov ip, hi(imm64)
185788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov.i32 d0[1], ip
185888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            // vmov d1, d0
185988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            {
186088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              UseScratchRegisterScope temps(this);
186188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois              Register scratch = temps.Acquire();
1862aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              {
1863960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell                CodeBufferCheckScope scope(this,
1864960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell                                           2 * kMaxInstructionSizeInBytes);
1865aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1866aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              }
1867aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              {
1868aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1869aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                vmov(cond,
1870aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                     Untyped32,
1871aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                     DRegisterLane(rd.GetLowDRegister(), 1),
1872aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley                     scratch);
1873aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              }
1874aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
18758885c17bce593f82cf90c086da242e52943c50efVincent Belliard              vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
187688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            }
187788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            return;
187888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
187988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
188088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        default:
188188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          break;
188288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
1883960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1884960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
188588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // mov ip, imm32
1886960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        // vdup.16 d0, ip
188788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
188888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
1889aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
1890960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1891aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1892aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
189388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        DataTypeValue vdup_dt = Untyped32;
189488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        switch (dt.GetValue()) {
189588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          case I16:
189688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            vdup_dt = Untyped16;
189788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            break;
189888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          case I32:
189988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            vdup_dt = Untyped32;
190088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            break;
190188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          default:
190288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            VIXL_UNREACHABLE();
190388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
1904aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1905283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vdup(cond, vdup_dt, rd, scratch);
1906283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
190788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
190888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
190988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Punt to vmov.i64
191088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        float f = neon_imm.GetImmediate<float>();
1911960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1912283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        vmov(cond, I32, rd, FloatToRawbits(f));
1913283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
191488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
191588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1916960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        // Use vmov to create the double in the low D register, then duplicate
1917960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        // it into the high D register.
191888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        double d = neon_imm.GetImmediate<double>();
1919960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        CodeBufferCheckScope scope(this, 7 * kMaxInstructionSizeInBytes);
1920960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        vmov(cond, F64, rd.GetLowDRegister(), d);
1921960c80d57d7ec81ad517b9f5117434ca930f05c6Martyn Capewell        vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1922283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois        return;
192388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
192488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
192588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
192688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
192788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
192888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
192988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
193088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
1931f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              InstructionCondRL instruction,
1932f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Condition cond,
1933f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Register rt,
1934f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Label* label) {
1935f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT((type == kLdrb) || (type == kLdrh) || (type == kLdrsb) ||
1936f8c2284645ce651f99ba410a512279102851076eJacob Bramley              (type == kLdrsh));
1937f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1938f8c2284645ce651f99ba410a512279102851076eJacob Bramley  CONTEXT_SCOPE;
1939f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1940f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if (label->IsBound()) {
194189d2f7702f0dc1751574bd5f9d35b5182fc65facJacob Bramley    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
1942f8c2284645ce651f99ba410a512279102851076eJacob Bramley    UseScratchRegisterScope temps(this);
1943f8c2284645ce651f99ba410a512279102851076eJacob Bramley    temps.Include(rt);
1944f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register scratch = temps.Acquire();
1945f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t mask = GetOffsetMask(type, Offset);
1946f8c2284645ce651f99ba410a512279102851076eJacob Bramley    switch (type) {
1947f8c2284645ce651f99ba410a512279102851076eJacob Bramley      case kLdrb:
1948f8c2284645ce651f99ba410a512279102851076eJacob Bramley        ldrb(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1949f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return;
1950f8c2284645ce651f99ba410a512279102851076eJacob Bramley      case kLdrh:
1951f8c2284645ce651f99ba410a512279102851076eJacob Bramley        ldrh(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1952f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return;
1953f8c2284645ce651f99ba410a512279102851076eJacob Bramley      case kLdrsb:
1954f8c2284645ce651f99ba410a512279102851076eJacob Bramley        ldrsb(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1955f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return;
1956f8c2284645ce651f99ba410a512279102851076eJacob Bramley      case kLdrsh:
1957f8c2284645ce651f99ba410a512279102851076eJacob Bramley        ldrsh(rt, MemOperandComputationHelper(cond, scratch, label, mask));
1958f8c2284645ce651f99ba410a512279102851076eJacob Bramley        return;
1959f8c2284645ce651f99ba410a512279102851076eJacob Bramley      default:
1960f8c2284645ce651f99ba410a512279102851076eJacob Bramley        VIXL_UNREACHABLE();
1961f8c2284645ce651f99ba410a512279102851076eJacob Bramley    }
1962f8c2284645ce651f99ba410a512279102851076eJacob Bramley    return;
1963f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
1964f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1965f8c2284645ce651f99ba410a512279102851076eJacob Bramley  Assembler::Delegate(type, instruction, cond, rt, label);
1966f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
1967f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1968f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1969f8c2284645ce651f99ba410a512279102851076eJacob Bramleyvoid MacroAssembler::Delegate(InstructionType type,
1970f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              InstructionCondRRL instruction,
1971f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Condition cond,
1972f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Register rt,
1973f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Register rt2,
1974f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Label* label) {
1975f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(type == kLdrd);
1976f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1977f8c2284645ce651f99ba410a512279102851076eJacob Bramley  CONTEXT_SCOPE;
1978f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1979f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if (label->IsBound()) {
198089d2f7702f0dc1751574bd5f9d35b5182fc65facJacob Bramley    CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1981f8c2284645ce651f99ba410a512279102851076eJacob Bramley    UseScratchRegisterScope temps(this);
1982f8c2284645ce651f99ba410a512279102851076eJacob Bramley    temps.Include(rt, rt2);
1983f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register scratch = temps.Acquire();
1984f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t mask = GetOffsetMask(type, Offset);
1985f8c2284645ce651f99ba410a512279102851076eJacob Bramley    ldrd(rt, rt2, MemOperandComputationHelper(cond, scratch, label, mask));
1986f8c2284645ce651f99ba410a512279102851076eJacob Bramley    return;
1987f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
1988f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1989f8c2284645ce651f99ba410a512279102851076eJacob Bramley  Assembler::Delegate(type, instruction, cond, rt, rt2, label);
1990f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
1991f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1992f8c2284645ce651f99ba410a512279102851076eJacob Bramley
1993f8c2284645ce651f99ba410a512279102851076eJacob Bramleyvoid MacroAssembler::Delegate(InstructionType type,
199488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondSizeRMop instruction,
199588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
199688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              EncodingSize size,
199788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rd,
199888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const MemOperand& operand) {
199921d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
200088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(size.IsBest());
2001fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli  VIXL_ASSERT((type == kLdr) || (type == kLdrb) || (type == kLdrh) ||
2002fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli              (type == kLdrsb) || (type == kLdrsh) || (type == kStr) ||
2003fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli              (type == kStrb) || (type == kStrh));
200488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
200588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const Register& rn = operand.GetBaseRegister();
200688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
200788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int32_t offset = operand.GetOffsetImmediate();
2008b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
2009b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    // Try to maximize the offset used by the MemOperand (load_store_offset).
2010b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    // Add the part which can't be used by the MemOperand (add_offset).
2011b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t load_store_offset = offset & extra_offset_mask;
2012b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t add_offset = offset & ~extra_offset_mask;
2013b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    if ((add_offset != 0) &&
2014b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard        (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
2015b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard      load_store_offset = 0;
2016b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard      add_offset = offset;
2017fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli    }
2018fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli    switch (addrmode) {
2019fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli      case PreIndex:
2020fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Avoid the unpredictable case 'str r0, [r0, imm]!'
2021fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        if (!rn.Is(rd)) {
2022a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          // Pre-Indexed case:
2023a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          // ldr r0, [r1, 12345]! will translate into
2024a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          //   add r1, r1, 12345
202588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          //   ldr r0, [r1]
2026aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
2027a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2028b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard            add(cond, rn, rn, add_offset);
2029aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
2030aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
2031aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2032a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard            (this->*instruction)(cond,
2033a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard                                 size,
2034a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard                                 rd,
2035a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard                                 MemOperand(rn, load_store_offset, PreIndex));
2036a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          }
2037a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          return;
2038fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        }
2039fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        break;
2040fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli      case Offset: {
2041fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        UseScratchRegisterScope temps(this);
2042fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Allow using the destination as a scratch register if possible.
2043fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
2044fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            !rd.Is(rn)) {
2045fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          temps.Include(rd);
2046fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        }
2047fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        Register scratch = temps.Acquire();
2048fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Offset case:
2049fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // ldr r0, [r1, 12345] will translate into
2050fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        //   add r0, r1, 12345
2051fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        //   ldr r0, [r0]
2052fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        {
2053fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2054b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard          add(cond, scratch, rn, add_offset);
2055fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        }
2056fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        {
2057fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2058fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          (this->*instruction)(cond,
2059fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli                               size,
2060fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli                               rd,
2061fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli                               MemOperand(scratch, load_store_offset));
2062fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        }
2063fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        return;
2064fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli      }
2065fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli      case PostIndex:
2066fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Avoid the unpredictable case 'ldr r0, [r0], imm'
2067fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        if (!rn.Is(rd)) {
2068fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          // Post-indexed case:
2069fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          // ldr r0. [r1], imm32 will translate into
2070fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   ldr r0, [r1]
2071fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   movw ip. imm32 & 0xffffffff
2072fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   movt ip, imm32 >> 16
2073fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   add r1, r1, ip
2074a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          {
2075a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2076a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard            (this->*instruction)(cond,
2077a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard                                 size,
2078a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard                                 rd,
2079fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli                                 MemOperand(rn, load_store_offset, PostIndex));
2080a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          }
2081fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          {
2082fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2083b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard            add(cond, rn, rn, add_offset);
2084a5372b10e91d4ecaddedc9c4aec2d61bf952a2caVincent Belliard          }
2085fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          return;
2086fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        }
2087fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        break;
208888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
2089fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli  } else if (operand.IsPlainRegister()) {
209088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const Register& rn = operand.GetBaseRegister();
209188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
209288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const Register& rm = operand.GetOffsetRegister();
2093fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli    if (rm.IsPC()) {
2094fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli      VIXL_ABORT_WITH_MSG(
2095fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          "The MacroAssembler does not convert loads and stores with a PC "
2096fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          "offset register.\n");
2097fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli    }
2098d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard    if (rn.IsPC()) {
2099d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard      if (addrmode == Offset) {
2100d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard        if (IsUsingT32()) {
2101d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard          VIXL_ABORT_WITH_MSG(
2102d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard              "The MacroAssembler does not convert loads and stores with a PC "
2103d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard              "base register for T32.\n");
2104d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard        }
2105d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard      } else {
2106d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard        VIXL_ABORT_WITH_MSG(
2107d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard            "The MacroAssembler does not convert loads and stores with a PC "
2108d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard            "base register in pre-index or post-index mode.\n");
2109d17e348e16bf0d6eca4f9ea0e935c7544098d045Vincent Belliard      }
2110fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli    }
211188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (addrmode) {
211288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PreIndex:
2113fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Avoid the unpredictable case 'str r0, [r0, imm]!'
2114fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        if (!rn.Is(rd)) {
2115fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          // Pre-Indexed case:
2116fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          // ldr r0, [r1, r2]! will translate into
2117fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   add r1, r1, r2
2118fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          //   ldr r0, [r1]
2119fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          {
2120fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2121fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            if (operand.GetSign().IsPlus()) {
2122fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli              add(cond, rn, rn, rm);
2123fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            } else {
2124fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli              sub(cond, rn, rn, rm);
2125fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            }
2126aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
2127fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          {
2128fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2129fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
2130fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          }
2131fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli          return;
2132aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2133fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        break;
213488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case Offset: {
213588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
2136fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Allow using the destination as a scratch register if this is not a
2137fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // store.
2138fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli        // Avoid using PC as a temporary as this has side-effects.
213988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
2140fad927c4321a9dd7e235b91aadd88f5542561370Georgia Kouveli            !rd.IsPC()) {
214188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          temps.Include(rd);
214288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
214388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
214488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Offset case:
214588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // ldr r0, [r1, r2] will translate into
214688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add r0, r1, r2
214788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   ldr r0, [r0]
2148aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2149aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2150aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          if (operand.GetSign().IsPlus()) {
2151aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            add(cond, scratch, rn, rm);
2152aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          } else {
2153aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            sub(cond, scratch, rn, rm);
2154aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
2155aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2156aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2157aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2158aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, size, rd, MemOperand(scratch, Offset));
215988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
216088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
216188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
216288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PostIndex:
216388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Avoid the unpredictable case 'ldr r0, [r0], imm'
216488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        if (!rn.Is(rd)) {
216588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          // Post-indexed case:
216688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          // ldr r0. [r1], r2 will translate into
216788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          //   ldr r0, [r1]
216888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          //   add r1, r1, r2
2169aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
2170aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2171aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
2172aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
2173aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
2174aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2175aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            if (operand.GetSign().IsPlus()) {
2176aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              add(cond, rn, rn, rm);
2177aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            } else {
2178aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley              sub(cond, rn, rn, rm);
2179aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            }
218088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
218188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          return;
218288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
218388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        break;
218488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
218588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
218688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, size, rd, operand);
218788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
218888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
218988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
219088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
219188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondRRMop instruction,
219288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
219388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rt,
219488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Register rt2,
219588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const MemOperand& operand) {
2196b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois  if ((type == kLdaexd) || (type == kLdrexd) || (type == kStlex) ||
2197b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois      (type == kStlexb) || (type == kStlexh) || (type == kStrex) ||
2198b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois      (type == kStrexb) || (type == kStrexh)) {
2199283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    UnimplementedDelegate(type);
2200283bbdf1908649c90069ff80dfca45de4f675de4Pierre Langlois    return;
2201b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois  }
2202b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois
2203b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois  VIXL_ASSERT((type == kLdrd) || (type == kStrd));
2204b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois
220521d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
220688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
22077f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois  // TODO: Should we allow these cases?
2208b44f7a6ee7f9cd194cde9577f5a941f2864795a4Pierre Langlois  if (IsUsingA32()) {
22097f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    // The first register needs to be even.
22107f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    if ((rt.GetCode() & 1) != 0) {
22117f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      UnimplementedDelegate(type);
22127f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      return;
22137f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    }
22147f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    // Registers need to be adjacent.
22157f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    if (((rt.GetCode() + 1) % kNumberOfRegisters) != rt2.GetCode()) {
22167f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      UnimplementedDelegate(type);
22177f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      return;
22187f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    }
22197f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    // LDRD lr, pc [...] is not allowed.
22207f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    if (rt.Is(lr)) {
22217f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      UnimplementedDelegate(type);
22227f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      return;
22237f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    }
222488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
222588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
22267f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois  if (operand.IsImmediate()) {
22277f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    const Register& rn = operand.GetBaseRegister();
22287f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
22297f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    int32_t offset = operand.GetOffsetImmediate();
2230b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
2231b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    // Try to maximize the offset used by the MemOperand (load_store_offset).
2232b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    // Add the part which can't be used by the MemOperand (add_offset).
2233b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t load_store_offset = offset & extra_offset_mask;
2234b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    uint32_t add_offset = offset & ~extra_offset_mask;
2235b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    if ((add_offset != 0) &&
2236b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard        (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
2237b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard      load_store_offset = 0;
2238b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard      add_offset = offset;
2239b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard    }
22407f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    switch (addrmode) {
22417f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case PreIndex: {
22427f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Allow using the destinations as a scratch registers if possible.
22437f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        UseScratchRegisterScope temps(this);
22447f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        if (type == kLdrd) {
22457f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt.Is(rn)) temps.Include(rt);
22467f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt2.Is(rn)) temps.Include(rt2);
224788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
22487f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois
22497f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Pre-Indexed case:
22507f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // ldrd r0, r1, [r2, 12345]! will translate into
22517f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   add r2, 12345
22527f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   ldrd r0, r1, [r2]
22537f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
22547f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2255b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard          add(cond, rn, rn, add_offset);
22567f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
22577f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
22587f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2259b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard          (this->*instruction)(cond,
2260b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               rt,
2261b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               rt2,
2262b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               MemOperand(rn, load_store_offset, PreIndex));
22637f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
22647f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        return;
226588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
22667f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case Offset: {
22677f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        UseScratchRegisterScope temps(this);
22687f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Allow using the destinations as a scratch registers if possible.
22697f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        if (type == kLdrd) {
22707f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt.Is(rn)) temps.Include(rt);
22717f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt2.Is(rn)) temps.Include(rt2);
22727f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
22737f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        Register scratch = temps.Acquire();
22747f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Offset case:
22757f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // ldrd r0, r1, [r2, 12345] will translate into
22767f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   add r0, r2, 12345
22777f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   ldrd r0, r1, [r0]
22787f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
22797f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2280b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard          add(cond, scratch, rn, add_offset);
22817f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
22827f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
22837f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2284b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard          (this->*instruction)(cond,
2285b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               rt,
2286b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               rt2,
2287b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                               MemOperand(scratch, load_store_offset));
22887f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
22897f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        return;
22907f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      }
22917f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case PostIndex:
22927f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Avoid the unpredictable case 'ldrd r0, r1, [r0], imm'
22937f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        if (!rn.Is(rt) && !rn.Is(rt2)) {
22947f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          // Post-indexed case:
22957f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          // ldrd r0, r1, [r2], imm32 will translate into
229688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          //   ldrd r0, r1, [r2]
22977f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          //   movw ip. imm32 & 0xffffffff
22987f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          //   movt ip, imm32 >> 16
22997f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          //   add r2, ip
2300aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
2301aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2302b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard            (this->*instruction)(cond,
2303b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                                 rt,
2304b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                                 rt2,
2305b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard                                 MemOperand(rn, load_store_offset, PostIndex));
2306aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
2307aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          {
23087f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2309b2838fee50499a1c7963167b0d8144552f194e15Vincent Belliard            add(cond, rn, rn, add_offset);
231088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
231188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          return;
23127f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23137f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        break;
23147f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    }
23157f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois  }
23167f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois  if (operand.IsPlainRegister()) {
23177f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    const Register& rn = operand.GetBaseRegister();
23187f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    const Register& rm = operand.GetOffsetRegister();
23197f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
23207f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois    switch (addrmode) {
23217f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case PreIndex:
23227f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // ldrd r0, r1, [r2, r3]! will translate into
23237f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   add r2, r3
23247f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   ldrd r0, r1, [r2]
23257f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23267f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23277f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (operand.GetSign().IsPlus()) {
23287f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            add(cond, rn, rn, rm);
23297f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          } else {
23307f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            sub(cond, rn, rn, rm);
233188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
23327f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23337f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23347f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23357f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
23367f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23377f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        return;
23387f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case PostIndex:
23397f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // ldrd r0, r1, [r2], r3 will translate into
23407f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   ldrd r0, r1, [r2]
23417f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   add r2, r3
23427f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23437f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23447f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
23457f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23467f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23477f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23487f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (operand.GetSign().IsPlus()) {
23497f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            add(cond, rn, rn, rm);
23507f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          } else {
23517f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            sub(cond, rn, rn, rm);
2352aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          }
23537f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23547f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        return;
23557f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois      case Offset: {
23567f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        UseScratchRegisterScope temps(this);
23577f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Allow using the destinations as a scratch registers if possible.
23587f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        if (type == kLdrd) {
23597f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt.Is(rn)) temps.Include(rt);
23607f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (!rt2.Is(rn)) temps.Include(rt2);
23617f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23627f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        Register scratch = temps.Acquire();
23637f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // Offset case:
23647f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        // ldrd r0, r1, [r2, r3] will translate into
23657f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   add r0, r2, r3
23667f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        //   ldrd r0, r1, [r0]
23677f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23687f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23697f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          if (operand.GetSign().IsPlus()) {
23707f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            add(cond, scratch, rn, rm);
23717f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          } else {
23727f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois            sub(cond, scratch, rn, rm);
237388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
237488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
23757f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        {
23767f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
23777f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois          (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
23787f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        }
23797f2a44c6dce08e942080f14af19f83a202162104Pierre Langlois        return;
238088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
238188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
238288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
238388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, rt, rt2, operand);
238488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
238588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
238688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
238788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
238888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondDtSMop instruction,
238988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
239088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DataType dt,
239188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              SRegister rd,
239288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const MemOperand& operand) {
239321d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
239488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
239588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const Register& rn = operand.GetBaseRegister();
239688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
239788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int32_t offset = operand.GetOffsetImmediate();
2398df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2399df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2400df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    if (rn.IsPC()) {
2401df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell      VIXL_ABORT_WITH_MSG(
2402df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          "The MacroAssembler does not convert vldr or vstr with a PC base "
2403df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          "register.\n");
2404df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    }
240588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (addrmode) {
240688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PreIndex:
240788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Pre-Indexed case:
240888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.32 s0, [r1, 12345]! will translate into
240988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add r1, 12345
241088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.32 s0, [r1]
2411df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell        if (offset != 0) {
2412df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2413df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, rn, rn, offset);
2414aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2415aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2416aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2417aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
241888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
241988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
242088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case Offset: {
242188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
242288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
242388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Offset case:
242488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.32 s0, [r1, 12345] will translate into
242588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add ip, r1, 12345
242688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.32 s0, [ip]
2427aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2428df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          VIXL_ASSERT(offset != 0);
2429df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2430df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, scratch, rn, offset);
2431aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2432aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2433aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2434aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
243588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
243688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
243788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
243888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PostIndex:
243988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Post-indexed case:
244088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.32 s0, [r1], imm32 will translate into
244188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.32 s0, [r1]
244288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   movw ip. imm32 & 0xffffffff
244388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   movt ip, imm32 >> 16
244488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add r1, ip
2445aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2446aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2447aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2448aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2449df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell        if (offset != 0) {
2450df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2451df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, rn, rn, offset);
245288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
245388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
245488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
245588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
245688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
245788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
245888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
245988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
246088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
246188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              InstructionCondDtDMop instruction,
246288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
246388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DataType dt,
246488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              DRegister rd,
246588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const MemOperand& operand) {
246621d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell  CONTEXT_SCOPE;
246788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if (operand.IsImmediate()) {
246888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    const Register& rn = operand.GetBaseRegister();
246988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    AddrMode addrmode = operand.GetAddrMode();
247088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    int32_t offset = operand.GetOffsetImmediate();
2471df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2472df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2473df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    if (rn.IsPC()) {
2474df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell      VIXL_ABORT_WITH_MSG(
2475df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          "The MacroAssembler does not convert vldr or vstr with a PC base "
2476df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          "register.\n");
2477df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell    }
247888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    switch (addrmode) {
247988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PreIndex:
248088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Pre-Indexed case:
248188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.64 d0, [r1, 12345]! will translate into
248288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add r1, 12345
248388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.64 d0, [r1]
2484df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell        if (offset != 0) {
2485df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2486df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, rn, rn, offset);
2487aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2488aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2489aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2490aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
249188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
249288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
249388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case Offset: {
249488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        UseScratchRegisterScope temps(this);
249588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        Register scratch = temps.Acquire();
249688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Offset case:
249788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.64 d0, [r1, 12345] will translate into
249888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add ip, r1, 12345
249988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.32 s0, [ip]
2500aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2501df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          VIXL_ASSERT(offset != 0);
2502df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2503df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, scratch, rn, offset);
2504aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2505aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2506aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2507aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
250888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
250988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
251088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
251188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      case PostIndex:
251288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // Post-indexed case:
251388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        // vldr.64 d0. [r1], imm32 will translate into
251488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   vldr.64 d0, [r1]
251588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   movw ip. imm32 & 0xffffffff
251688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   movt ip, imm32 >> 16
251788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        //   add r1, ip
2518aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        {
2519aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2520aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2521aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley        }
2522df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell        if (offset != 0) {
2523df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2524df9f46669cb7ea55844ab6e5ac0b12c26399b233Martyn Capewell          add(cond, rn, rn, offset);
252588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        }
252688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        return;
252788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    }
252888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
252988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
253088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
253188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
253288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
253388c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisvoid MacroAssembler::Delegate(InstructionType type,
2534a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli                              InstructionCondMsrOp instruction,
253588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              Condition cond,
253688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              MaskedSpecialRegister spec_reg,
253788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                              const Operand& operand) {
253888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  USE(type);
253988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  VIXL_ASSERT(type == kMsr);
2540a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli  if (operand.IsImmediate()) {
2541a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    UseScratchRegisterScope temps(this);
2542a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    Register scratch = temps.Acquire();
2543a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    {
2544a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
2545a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli      mov(cond, scratch, operand);
2546a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    }
2547aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2548a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    msr(cond, spec_reg, scratch);
2549a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli    return;
2550aaac397e490f27ca3011e8ba2cb61f4f455c1a4dJacob Bramley  }
2551a01fbf25f9e2c9c53e82774126c4717ee37c1d91Georgia Kouveli  Assembler::Delegate(type, instruction, cond, spec_reg, operand);
255288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}
255388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
2554f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2555f8c2284645ce651f99ba410a512279102851076eJacob Bramleyvoid MacroAssembler::Delegate(InstructionType type,
2556f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              InstructionCondDtDL instruction,
2557f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Condition cond,
2558f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              DataType dt,
2559f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              DRegister rd,
2560f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Label* label) {
2561f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(type == kVldr);
2562f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2563f8c2284645ce651f99ba410a512279102851076eJacob Bramley  CONTEXT_SCOPE;
2564f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2565f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if (label->IsBound()) {
256689d2f7702f0dc1751574bd5f9d35b5182fc65facJacob Bramley    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2567f8c2284645ce651f99ba410a512279102851076eJacob Bramley    UseScratchRegisterScope temps(this);
2568f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register scratch = temps.Acquire();
2569f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t mask = GetOffsetMask(type, Offset);
2570f8c2284645ce651f99ba410a512279102851076eJacob Bramley    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, label, mask));
2571f8c2284645ce651f99ba410a512279102851076eJacob Bramley    return;
2572f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
2573f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2574f8c2284645ce651f99ba410a512279102851076eJacob Bramley  Assembler::Delegate(type, instruction, cond, dt, rd, label);
2575f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
2576f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2577f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2578f8c2284645ce651f99ba410a512279102851076eJacob Bramleyvoid MacroAssembler::Delegate(InstructionType type,
2579f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              InstructionCondDtSL instruction,
2580f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Condition cond,
2581f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              DataType dt,
2582f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              SRegister rd,
2583f8c2284645ce651f99ba410a512279102851076eJacob Bramley                              Label* label) {
2584f8c2284645ce651f99ba410a512279102851076eJacob Bramley  VIXL_ASSERT(type == kVldr);
2585f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2586f8c2284645ce651f99ba410a512279102851076eJacob Bramley  CONTEXT_SCOPE;
2587f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2588f8c2284645ce651f99ba410a512279102851076eJacob Bramley  if (label->IsBound()) {
258989d2f7702f0dc1751574bd5f9d35b5182fc65facJacob Bramley    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2590f8c2284645ce651f99ba410a512279102851076eJacob Bramley    UseScratchRegisterScope temps(this);
2591f8c2284645ce651f99ba410a512279102851076eJacob Bramley    Register scratch = temps.Acquire();
2592f8c2284645ce651f99ba410a512279102851076eJacob Bramley    uint32_t mask = GetOffsetMask(type, Offset);
2593f8c2284645ce651f99ba410a512279102851076eJacob Bramley    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, label, mask));
2594f8c2284645ce651f99ba410a512279102851076eJacob Bramley    return;
2595f8c2284645ce651f99ba410a512279102851076eJacob Bramley  }
2596f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2597f8c2284645ce651f99ba410a512279102851076eJacob Bramley  Assembler::Delegate(type, instruction, cond, dt, rd, label);
2598f8c2284645ce651f99ba410a512279102851076eJacob Bramley}
2599f8c2284645ce651f99ba410a512279102851076eJacob Bramley
2600f8c2284645ce651f99ba410a512279102851076eJacob Bramley
260121d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#undef CONTEXT_SCOPE
260221d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#undef TOSTRING
260321d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell#undef STRINGIFY
260421d8d8d551fc50cb15fc137f00a154ea65eb2b81Martyn Capewell
260588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// Start of generated code.
260688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois// End of generated code.
260788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}  // namespace aarch32
260888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois}  // namespace vixl
2609