1b8021494Sopenharmony_ci// Copyright 2017, VIXL authors
2b8021494Sopenharmony_ci// All rights reserved.
3b8021494Sopenharmony_ci//
4b8021494Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
5b8021494Sopenharmony_ci// modification, are permitted provided that the following conditions are met:
6b8021494Sopenharmony_ci//
7b8021494Sopenharmony_ci//   * Redistributions of source code must retain the above copyright notice,
8b8021494Sopenharmony_ci//     this list of conditions and the following disclaimer.
9b8021494Sopenharmony_ci//   * Redistributions in binary form must reproduce the above copyright
10b8021494Sopenharmony_ci//     notice, this list of conditions and the following disclaimer in the
11b8021494Sopenharmony_ci//     documentation and/or other materials provided with the distribution.
12b8021494Sopenharmony_ci//   * Neither the name of ARM Limited nor the names of its contributors may
13b8021494Sopenharmony_ci//     be used to endorse or promote products derived from this software
14b8021494Sopenharmony_ci//     without specific prior written permission.
15b8021494Sopenharmony_ci//
16b8021494Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17b8021494Sopenharmony_ci// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b8021494Sopenharmony_ci// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b8021494Sopenharmony_ci// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20b8021494Sopenharmony_ci// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21b8021494Sopenharmony_ci// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22b8021494Sopenharmony_ci// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23b8021494Sopenharmony_ci// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24b8021494Sopenharmony_ci// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25b8021494Sopenharmony_ci// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26b8021494Sopenharmony_ci// POSSIBILITY OF SUCH DAMAGE.
27b8021494Sopenharmony_ci
28b8021494Sopenharmony_ci#include "aarch32/macro-assembler-aarch32.h"
29b8021494Sopenharmony_ci
30b8021494Sopenharmony_ci#define STRINGIFY(x) #x
31b8021494Sopenharmony_ci#define TOSTRING(x) STRINGIFY(x)
32b8021494Sopenharmony_ci
33b8021494Sopenharmony_ci#define CONTEXT_SCOPE \
34b8021494Sopenharmony_ci  ContextScope context(this, __FILE__ ":" TOSTRING(__LINE__))
35b8021494Sopenharmony_ci
36b8021494Sopenharmony_cinamespace vixl {
37b8021494Sopenharmony_cinamespace aarch32 {
38b8021494Sopenharmony_ci
39b8021494Sopenharmony_ciExactAssemblyScopeWithoutPoolsCheck::ExactAssemblyScopeWithoutPoolsCheck(
40b8021494Sopenharmony_ci    MacroAssembler* masm, size_t size, SizePolicy size_policy)
41b8021494Sopenharmony_ci    : ExactAssemblyScope(masm,
42b8021494Sopenharmony_ci                         size,
43b8021494Sopenharmony_ci                         size_policy,
44b8021494Sopenharmony_ci                         ExactAssemblyScope::kIgnorePools) {}
45b8021494Sopenharmony_ci
46b8021494Sopenharmony_civoid UseScratchRegisterScope::Open(MacroAssembler* masm) {
47b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ == NULL);
48b8021494Sopenharmony_ci  VIXL_ASSERT(masm != NULL);
49b8021494Sopenharmony_ci  masm_ = masm;
50b8021494Sopenharmony_ci
51b8021494Sopenharmony_ci  old_available_ = masm_->GetScratchRegisterList()->GetList();
52b8021494Sopenharmony_ci  old_available_vfp_ = masm_->GetScratchVRegisterList()->GetList();
53b8021494Sopenharmony_ci
54b8021494Sopenharmony_ci  parent_ = masm->GetCurrentScratchRegisterScope();
55b8021494Sopenharmony_ci  masm->SetCurrentScratchRegisterScope(this);
56b8021494Sopenharmony_ci}
57b8021494Sopenharmony_ci
58b8021494Sopenharmony_ci
59b8021494Sopenharmony_civoid UseScratchRegisterScope::Close() {
60b8021494Sopenharmony_ci  if (masm_ != NULL) {
61b8021494Sopenharmony_ci    // Ensure that scopes nest perfectly, and do not outlive their parents.
62b8021494Sopenharmony_ci    // This is a run-time check because the order of destruction of objects in
63b8021494Sopenharmony_ci    // the _same_ scope is implementation-defined, and is likely to change in
64b8021494Sopenharmony_ci    // optimised builds.
65b8021494Sopenharmony_ci    VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
66b8021494Sopenharmony_ci    masm_->SetCurrentScratchRegisterScope(parent_);
67b8021494Sopenharmony_ci
68b8021494Sopenharmony_ci    masm_->GetScratchRegisterList()->SetList(old_available_);
69b8021494Sopenharmony_ci    masm_->GetScratchVRegisterList()->SetList(old_available_vfp_);
70b8021494Sopenharmony_ci
71b8021494Sopenharmony_ci    masm_ = NULL;
72b8021494Sopenharmony_ci  }
73b8021494Sopenharmony_ci}
74b8021494Sopenharmony_ci
75b8021494Sopenharmony_ci
76b8021494Sopenharmony_cibool UseScratchRegisterScope::IsAvailable(const Register& reg) const {
77b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
78b8021494Sopenharmony_ci  VIXL_ASSERT(reg.IsValid());
79b8021494Sopenharmony_ci  return masm_->GetScratchRegisterList()->Includes(reg);
80b8021494Sopenharmony_ci}
81b8021494Sopenharmony_ci
82b8021494Sopenharmony_ci
83b8021494Sopenharmony_cibool UseScratchRegisterScope::IsAvailable(const VRegister& reg) const {
84b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
85b8021494Sopenharmony_ci  VIXL_ASSERT(reg.IsValid());
86b8021494Sopenharmony_ci  return masm_->GetScratchVRegisterList()->IncludesAllOf(reg);
87b8021494Sopenharmony_ci}
88b8021494Sopenharmony_ci
89b8021494Sopenharmony_ci
90b8021494Sopenharmony_ciRegister UseScratchRegisterScope::Acquire() {
91b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
92b8021494Sopenharmony_ci  Register reg = masm_->GetScratchRegisterList()->GetFirstAvailableRegister();
93b8021494Sopenharmony_ci  VIXL_CHECK(reg.IsValid());
94b8021494Sopenharmony_ci  masm_->GetScratchRegisterList()->Remove(reg);
95b8021494Sopenharmony_ci  return reg;
96b8021494Sopenharmony_ci}
97b8021494Sopenharmony_ci
98b8021494Sopenharmony_ci
99b8021494Sopenharmony_ciVRegister UseScratchRegisterScope::AcquireV(unsigned size_in_bits) {
100b8021494Sopenharmony_ci  switch (size_in_bits) {
101b8021494Sopenharmony_ci    case kSRegSizeInBits:
102b8021494Sopenharmony_ci      return AcquireS();
103b8021494Sopenharmony_ci    case kDRegSizeInBits:
104b8021494Sopenharmony_ci      return AcquireD();
105b8021494Sopenharmony_ci    case kQRegSizeInBits:
106b8021494Sopenharmony_ci      return AcquireQ();
107b8021494Sopenharmony_ci    default:
108b8021494Sopenharmony_ci      VIXL_UNREACHABLE();
109b8021494Sopenharmony_ci      return NoVReg;
110b8021494Sopenharmony_ci  }
111b8021494Sopenharmony_ci}
112b8021494Sopenharmony_ci
113b8021494Sopenharmony_ci
114b8021494Sopenharmony_ciQRegister UseScratchRegisterScope::AcquireQ() {
115b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
116b8021494Sopenharmony_ci  QRegister reg =
117b8021494Sopenharmony_ci      masm_->GetScratchVRegisterList()->GetFirstAvailableQRegister();
118b8021494Sopenharmony_ci  VIXL_CHECK(reg.IsValid());
119b8021494Sopenharmony_ci  masm_->GetScratchVRegisterList()->Remove(reg);
120b8021494Sopenharmony_ci  return reg;
121b8021494Sopenharmony_ci}
122b8021494Sopenharmony_ci
123b8021494Sopenharmony_ci
124b8021494Sopenharmony_ciDRegister UseScratchRegisterScope::AcquireD() {
125b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
126b8021494Sopenharmony_ci  DRegister reg =
127b8021494Sopenharmony_ci      masm_->GetScratchVRegisterList()->GetFirstAvailableDRegister();
128b8021494Sopenharmony_ci  VIXL_CHECK(reg.IsValid());
129b8021494Sopenharmony_ci  masm_->GetScratchVRegisterList()->Remove(reg);
130b8021494Sopenharmony_ci  return reg;
131b8021494Sopenharmony_ci}
132b8021494Sopenharmony_ci
133b8021494Sopenharmony_ci
134b8021494Sopenharmony_ciSRegister UseScratchRegisterScope::AcquireS() {
135b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
136b8021494Sopenharmony_ci  SRegister reg =
137b8021494Sopenharmony_ci      masm_->GetScratchVRegisterList()->GetFirstAvailableSRegister();
138b8021494Sopenharmony_ci  VIXL_CHECK(reg.IsValid());
139b8021494Sopenharmony_ci  masm_->GetScratchVRegisterList()->Remove(reg);
140b8021494Sopenharmony_ci  return reg;
141b8021494Sopenharmony_ci}
142b8021494Sopenharmony_ci
143b8021494Sopenharmony_ci
144b8021494Sopenharmony_civoid UseScratchRegisterScope::Release(const Register& reg) {
145b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
146b8021494Sopenharmony_ci  VIXL_ASSERT(reg.IsValid());
147b8021494Sopenharmony_ci  VIXL_ASSERT(!masm_->GetScratchRegisterList()->Includes(reg));
148b8021494Sopenharmony_ci  masm_->GetScratchRegisterList()->Combine(reg);
149b8021494Sopenharmony_ci}
150b8021494Sopenharmony_ci
151b8021494Sopenharmony_ci
152b8021494Sopenharmony_civoid UseScratchRegisterScope::Release(const VRegister& reg) {
153b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
154b8021494Sopenharmony_ci  VIXL_ASSERT(reg.IsValid());
155b8021494Sopenharmony_ci  VIXL_ASSERT(!masm_->GetScratchVRegisterList()->IncludesAliasOf(reg));
156b8021494Sopenharmony_ci  masm_->GetScratchVRegisterList()->Combine(reg);
157b8021494Sopenharmony_ci}
158b8021494Sopenharmony_ci
159b8021494Sopenharmony_ci
160b8021494Sopenharmony_civoid UseScratchRegisterScope::Include(const RegisterList& list) {
161b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
162b8021494Sopenharmony_ci  RegisterList excluded_registers(sp, lr, pc);
163b8021494Sopenharmony_ci  uint32_t mask = list.GetList() & ~excluded_registers.GetList();
164b8021494Sopenharmony_ci  RegisterList* available = masm_->GetScratchRegisterList();
165b8021494Sopenharmony_ci  available->SetList(available->GetList() | mask);
166b8021494Sopenharmony_ci}
167b8021494Sopenharmony_ci
168b8021494Sopenharmony_ci
169b8021494Sopenharmony_civoid UseScratchRegisterScope::Include(const VRegisterList& list) {
170b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
171b8021494Sopenharmony_ci  VRegisterList* available = masm_->GetScratchVRegisterList();
172b8021494Sopenharmony_ci  available->SetList(available->GetList() | list.GetList());
173b8021494Sopenharmony_ci}
174b8021494Sopenharmony_ci
175b8021494Sopenharmony_ci
176b8021494Sopenharmony_civoid UseScratchRegisterScope::Exclude(const RegisterList& list) {
177b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
178b8021494Sopenharmony_ci  RegisterList* available = masm_->GetScratchRegisterList();
179b8021494Sopenharmony_ci  available->SetList(available->GetList() & ~list.GetList());
180b8021494Sopenharmony_ci}
181b8021494Sopenharmony_ci
182b8021494Sopenharmony_ci
183b8021494Sopenharmony_civoid UseScratchRegisterScope::Exclude(const VRegisterList& list) {
184b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
185b8021494Sopenharmony_ci  VRegisterList* available = masm_->GetScratchVRegisterList();
186b8021494Sopenharmony_ci  available->SetList(available->GetList() & ~list.GetList());
187b8021494Sopenharmony_ci}
188b8021494Sopenharmony_ci
189b8021494Sopenharmony_ci
190b8021494Sopenharmony_civoid UseScratchRegisterScope::Exclude(const Operand& operand) {
191b8021494Sopenharmony_ci  if (operand.IsImmediateShiftedRegister()) {
192b8021494Sopenharmony_ci    Exclude(operand.GetBaseRegister());
193b8021494Sopenharmony_ci  } else if (operand.IsRegisterShiftedRegister()) {
194b8021494Sopenharmony_ci    Exclude(operand.GetBaseRegister(), operand.GetShiftRegister());
195b8021494Sopenharmony_ci  } else {
196b8021494Sopenharmony_ci    VIXL_ASSERT(operand.IsImmediate());
197b8021494Sopenharmony_ci  }
198b8021494Sopenharmony_ci}
199b8021494Sopenharmony_ci
200b8021494Sopenharmony_ci
201b8021494Sopenharmony_civoid UseScratchRegisterScope::ExcludeAll() {
202b8021494Sopenharmony_ci  VIXL_ASSERT(masm_ != NULL);
203b8021494Sopenharmony_ci  masm_->GetScratchRegisterList()->SetList(0);
204b8021494Sopenharmony_ci  masm_->GetScratchVRegisterList()->SetList(0);
205b8021494Sopenharmony_ci}
206b8021494Sopenharmony_ci
207b8021494Sopenharmony_ci
208b8021494Sopenharmony_civoid MacroAssembler::EnsureEmitPoolsFor(size_t size_arg) {
209b8021494Sopenharmony_ci  // We skip the check when the pools are blocked.
210b8021494Sopenharmony_ci  if (ArePoolsBlocked()) return;
211b8021494Sopenharmony_ci
212b8021494Sopenharmony_ci  VIXL_ASSERT(IsUint32(size_arg));
213b8021494Sopenharmony_ci  uint32_t size = static_cast<uint32_t>(size_arg);
214b8021494Sopenharmony_ci
215b8021494Sopenharmony_ci  if (pool_manager_.MustEmit(GetCursorOffset(), size)) {
216b8021494Sopenharmony_ci    int32_t new_pc = pool_manager_.Emit(this, GetCursorOffset(), size);
217b8021494Sopenharmony_ci    VIXL_ASSERT(new_pc == GetCursorOffset());
218b8021494Sopenharmony_ci    USE(new_pc);
219b8021494Sopenharmony_ci  }
220b8021494Sopenharmony_ci}
221b8021494Sopenharmony_ci
222b8021494Sopenharmony_ci
223b8021494Sopenharmony_civoid MacroAssembler::HandleOutOfBoundsImmediate(Condition cond,
224b8021494Sopenharmony_ci                                                Register tmp,
225b8021494Sopenharmony_ci                                                uint32_t imm) {
226b8021494Sopenharmony_ci  if (IsUintN(16, imm)) {
227b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
228b8021494Sopenharmony_ci    mov(cond, tmp, imm & 0xffff);
229b8021494Sopenharmony_ci    return;
230b8021494Sopenharmony_ci  }
231b8021494Sopenharmony_ci  if (IsUsingT32()) {
232b8021494Sopenharmony_ci    if (ImmediateT32::IsImmediateT32(~imm)) {
233b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
234b8021494Sopenharmony_ci      mvn(cond, tmp, ~imm);
235b8021494Sopenharmony_ci      return;
236b8021494Sopenharmony_ci    }
237b8021494Sopenharmony_ci  } else {
238b8021494Sopenharmony_ci    if (ImmediateA32::IsImmediateA32(~imm)) {
239b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
240b8021494Sopenharmony_ci      mvn(cond, tmp, ~imm);
241b8021494Sopenharmony_ci      return;
242b8021494Sopenharmony_ci    }
243b8021494Sopenharmony_ci  }
244b8021494Sopenharmony_ci  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
245b8021494Sopenharmony_ci  mov(cond, tmp, imm & 0xffff);
246b8021494Sopenharmony_ci  movt(cond, tmp, imm >> 16);
247b8021494Sopenharmony_ci}
248b8021494Sopenharmony_ci
249b8021494Sopenharmony_ci
250b8021494Sopenharmony_ciMemOperand MacroAssembler::MemOperandComputationHelper(
251b8021494Sopenharmony_ci    Condition cond,
252b8021494Sopenharmony_ci    Register scratch,
253b8021494Sopenharmony_ci    Register base,
254b8021494Sopenharmony_ci    uint32_t offset,
255b8021494Sopenharmony_ci    uint32_t extra_offset_mask) {
256b8021494Sopenharmony_ci  VIXL_ASSERT(!AliasesAvailableScratchRegister(scratch));
257b8021494Sopenharmony_ci  VIXL_ASSERT(!AliasesAvailableScratchRegister(base));
258b8021494Sopenharmony_ci  VIXL_ASSERT(allow_macro_instructions_);
259b8021494Sopenharmony_ci  VIXL_ASSERT(OutsideITBlock());
260b8021494Sopenharmony_ci
261b8021494Sopenharmony_ci  // Check for the simple pass-through case.
262b8021494Sopenharmony_ci  if ((offset & extra_offset_mask) == offset) return MemOperand(base, offset);
263b8021494Sopenharmony_ci
264b8021494Sopenharmony_ci  MacroEmissionCheckScope guard(this);
265b8021494Sopenharmony_ci#ifndef PANDA_BUILD
266b8021494Sopenharmony_ci  ITScope it_scope(this, &cond, guard);
267b8021494Sopenharmony_ci#else
268b8021494Sopenharmony_ci  ITScope it_scope(allocator_, this, &cond, guard);
269b8021494Sopenharmony_ci#endif
270b8021494Sopenharmony_ci
271b8021494Sopenharmony_ci  uint32_t load_store_offset = offset & extra_offset_mask;
272b8021494Sopenharmony_ci  uint32_t add_offset = offset & ~extra_offset_mask;
273b8021494Sopenharmony_ci  if ((add_offset != 0) && (IsModifiedImmediate(offset) ||
274b8021494Sopenharmony_ci                            IsModifiedImmediate(UnsignedNegate(offset)))) {
275b8021494Sopenharmony_ci    load_store_offset = 0;
276b8021494Sopenharmony_ci    add_offset = offset;
277b8021494Sopenharmony_ci  }
278b8021494Sopenharmony_ci
279b8021494Sopenharmony_ci  if (base.IsPC()) {
280b8021494Sopenharmony_ci    // Special handling for PC bases. We must read the PC in the first
281b8021494Sopenharmony_ci    // instruction (and only in that instruction), and we must also take care to
282b8021494Sopenharmony_ci    // keep the same address calculation as loads and stores. For T32, that
283b8021494Sopenharmony_ci    // means using something like ADR, which uses AlignDown(PC, 4).
284b8021494Sopenharmony_ci
285b8021494Sopenharmony_ci    // We don't handle positive offsets from PC because the intention is not
286b8021494Sopenharmony_ci    // clear; does the user expect the offset from the current
287b8021494Sopenharmony_ci    // GetCursorOffset(), or to allow a certain amount of space after the
288b8021494Sopenharmony_ci    // instruction?
289b8021494Sopenharmony_ci    VIXL_ASSERT((offset & 0x80000000) != 0);
290b8021494Sopenharmony_ci    if (IsUsingT32()) {
291b8021494Sopenharmony_ci      // T32: make the first instruction "SUB (immediate, from PC)" -- an alias
292b8021494Sopenharmony_ci      // of ADR -- to get behaviour like loads and stores. This ADR can handle
293b8021494Sopenharmony_ci      // at least as much offset as the load_store_offset so it can replace it.
294b8021494Sopenharmony_ci
295b8021494Sopenharmony_ci      uint32_t sub_pc_offset = UnsignedNegate(offset) & 0xfff;
296b8021494Sopenharmony_ci      load_store_offset = (offset + sub_pc_offset) & extra_offset_mask;
297b8021494Sopenharmony_ci      add_offset = (offset + sub_pc_offset) & ~extra_offset_mask;
298b8021494Sopenharmony_ci
299b8021494Sopenharmony_ci      ExactAssemblyScope scope(this, k32BitT32InstructionSizeInBytes);
300b8021494Sopenharmony_ci      sub(cond, scratch, base, sub_pc_offset);
301b8021494Sopenharmony_ci
302b8021494Sopenharmony_ci      if (add_offset == 0) return MemOperand(scratch, load_store_offset);
303b8021494Sopenharmony_ci
304b8021494Sopenharmony_ci      // The rest of the offset can be generated in the usual way.
305b8021494Sopenharmony_ci      base = scratch;
306b8021494Sopenharmony_ci    }
307b8021494Sopenharmony_ci    // A32 can use any SUB instruction, so we don't have to do anything special
308b8021494Sopenharmony_ci    // here except to ensure that we read the PC first.
309b8021494Sopenharmony_ci  }
310b8021494Sopenharmony_ci
311b8021494Sopenharmony_ci  add(cond, scratch, base, add_offset);
312b8021494Sopenharmony_ci  return MemOperand(scratch, load_store_offset);
313b8021494Sopenharmony_ci}
314b8021494Sopenharmony_ci
315b8021494Sopenharmony_ci
316b8021494Sopenharmony_ciuint32_t MacroAssembler::GetOffsetMask(InstructionType type,
317b8021494Sopenharmony_ci                                       AddrMode addrmode) {
318b8021494Sopenharmony_ci  switch (type) {
319b8021494Sopenharmony_ci    case kLdr:
320b8021494Sopenharmony_ci    case kLdrb:
321b8021494Sopenharmony_ci    case kStr:
322b8021494Sopenharmony_ci    case kStrb:
323b8021494Sopenharmony_ci      if (IsUsingA32() || (addrmode == Offset)) {
324b8021494Sopenharmony_ci        return 0xfff;
325b8021494Sopenharmony_ci      } else {
326b8021494Sopenharmony_ci        return 0xff;
327b8021494Sopenharmony_ci      }
328b8021494Sopenharmony_ci    case kLdrsb:
329b8021494Sopenharmony_ci    case kLdrh:
330b8021494Sopenharmony_ci    case kLdrsh:
331b8021494Sopenharmony_ci    case kStrh:
332b8021494Sopenharmony_ci      if (IsUsingT32() && (addrmode == Offset)) {
333b8021494Sopenharmony_ci        return 0xfff;
334b8021494Sopenharmony_ci      } else {
335b8021494Sopenharmony_ci        return 0xff;
336b8021494Sopenharmony_ci      }
337b8021494Sopenharmony_ci    case kVldr:
338b8021494Sopenharmony_ci    case kVstr:
339b8021494Sopenharmony_ci      return 0x3fc;
340b8021494Sopenharmony_ci    case kLdrd:
341b8021494Sopenharmony_ci    case kStrd:
342b8021494Sopenharmony_ci      if (IsUsingA32()) {
343b8021494Sopenharmony_ci        return 0xff;
344b8021494Sopenharmony_ci      } else {
345b8021494Sopenharmony_ci        return 0x3fc;
346b8021494Sopenharmony_ci      }
347b8021494Sopenharmony_ci    default:
348b8021494Sopenharmony_ci      VIXL_UNREACHABLE();
349b8021494Sopenharmony_ci      return 0;
350b8021494Sopenharmony_ci  }
351b8021494Sopenharmony_ci}
352b8021494Sopenharmony_ci
353b8021494Sopenharmony_ci
354b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRRRR(
355b8021494Sopenharmony_ci    const char* format, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
356b8021494Sopenharmony_ci  printf(format, a, b, c, d);
357b8021494Sopenharmony_ci}
358b8021494Sopenharmony_ci
359b8021494Sopenharmony_ci
360b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRRRD(
361b8021494Sopenharmony_ci    const char* format, uint32_t a, uint32_t b, uint32_t c, double d) {
362b8021494Sopenharmony_ci  printf(format, a, b, c, d);
363b8021494Sopenharmony_ci}
364b8021494Sopenharmony_ci
365b8021494Sopenharmony_ci
366b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRRDR(
367b8021494Sopenharmony_ci    const char* format, uint32_t a, uint32_t b, double c, uint32_t d) {
368b8021494Sopenharmony_ci  printf(format, a, b, c, d);
369b8021494Sopenharmony_ci}
370b8021494Sopenharmony_ci
371b8021494Sopenharmony_ci
372b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRRDD(
373b8021494Sopenharmony_ci    const char* format, uint32_t a, uint32_t b, double c, double d) {
374b8021494Sopenharmony_ci  printf(format, a, b, c, d);
375b8021494Sopenharmony_ci}
376b8021494Sopenharmony_ci
377b8021494Sopenharmony_ci
378b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRDRR(
379b8021494Sopenharmony_ci    const char* format, uint32_t a, double b, uint32_t c, uint32_t d) {
380b8021494Sopenharmony_ci  printf(format, a, b, c, d);
381b8021494Sopenharmony_ci}
382b8021494Sopenharmony_ci
383b8021494Sopenharmony_ci
384b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRDRD(
385b8021494Sopenharmony_ci    const char* format, uint32_t a, double b, uint32_t c, double d) {
386b8021494Sopenharmony_ci  printf(format, a, b, c, d);
387b8021494Sopenharmony_ci}
388b8021494Sopenharmony_ci
389b8021494Sopenharmony_ci
390b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRDDR(
391b8021494Sopenharmony_ci    const char* format, uint32_t a, double b, double c, uint32_t d) {
392b8021494Sopenharmony_ci  printf(format, a, b, c, d);
393b8021494Sopenharmony_ci}
394b8021494Sopenharmony_ci
395b8021494Sopenharmony_ci
396b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineRDDD(
397b8021494Sopenharmony_ci    const char* format, uint32_t a, double b, double c, double d) {
398b8021494Sopenharmony_ci  printf(format, a, b, c, d);
399b8021494Sopenharmony_ci}
400b8021494Sopenharmony_ci
401b8021494Sopenharmony_ci
402b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDRRR(
403b8021494Sopenharmony_ci    const char* format, double a, uint32_t b, uint32_t c, uint32_t d) {
404b8021494Sopenharmony_ci  printf(format, a, b, c, d);
405b8021494Sopenharmony_ci}
406b8021494Sopenharmony_ci
407b8021494Sopenharmony_ci
408b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDRRD(
409b8021494Sopenharmony_ci    const char* format, double a, uint32_t b, uint32_t c, double d) {
410b8021494Sopenharmony_ci  printf(format, a, b, c, d);
411b8021494Sopenharmony_ci}
412b8021494Sopenharmony_ci
413b8021494Sopenharmony_ci
414b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDRDR(
415b8021494Sopenharmony_ci    const char* format, double a, uint32_t b, double c, uint32_t d) {
416b8021494Sopenharmony_ci  printf(format, a, b, c, d);
417b8021494Sopenharmony_ci}
418b8021494Sopenharmony_ci
419b8021494Sopenharmony_ci
420b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDRDD(
421b8021494Sopenharmony_ci    const char* format, double a, uint32_t b, double c, double d) {
422b8021494Sopenharmony_ci  printf(format, a, b, c, d);
423b8021494Sopenharmony_ci}
424b8021494Sopenharmony_ci
425b8021494Sopenharmony_ci
426b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDDRR(
427b8021494Sopenharmony_ci    const char* format, double a, double b, uint32_t c, uint32_t d) {
428b8021494Sopenharmony_ci  printf(format, a, b, c, d);
429b8021494Sopenharmony_ci}
430b8021494Sopenharmony_ci
431b8021494Sopenharmony_ci
432b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDDRD(
433b8021494Sopenharmony_ci    const char* format, double a, double b, uint32_t c, double d) {
434b8021494Sopenharmony_ci  printf(format, a, b, c, d);
435b8021494Sopenharmony_ci}
436b8021494Sopenharmony_ci
437b8021494Sopenharmony_ci
438b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDDDR(
439b8021494Sopenharmony_ci    const char* format, double a, double b, double c, uint32_t d) {
440b8021494Sopenharmony_ci  printf(format, a, b, c, d);
441b8021494Sopenharmony_ci}
442b8021494Sopenharmony_ci
443b8021494Sopenharmony_ci
444b8021494Sopenharmony_ciHARDFLOAT void PrintfTrampolineDDDD(
445b8021494Sopenharmony_ci    const char* format, double a, double b, double c, double d) {
446b8021494Sopenharmony_ci  printf(format, a, b, c, d);
447b8021494Sopenharmony_ci}
448b8021494Sopenharmony_ci
449b8021494Sopenharmony_ci
450b8021494Sopenharmony_civoid MacroAssembler::Printf(const char* format,
451b8021494Sopenharmony_ci                            CPURegister reg1,
452b8021494Sopenharmony_ci                            CPURegister reg2,
453b8021494Sopenharmony_ci                            CPURegister reg3,
454b8021494Sopenharmony_ci                            CPURegister reg4) {
455b8021494Sopenharmony_ci  // Exclude all registers from the available scratch registers, so
456b8021494Sopenharmony_ci  // that we are able to use ip below.
457b8021494Sopenharmony_ci  // TODO: Refactor this function to use UseScratchRegisterScope
458b8021494Sopenharmony_ci  // for temporary registers below.
459b8021494Sopenharmony_ci  UseScratchRegisterScope scratch(this);
460b8021494Sopenharmony_ci  scratch.ExcludeAll();
461b8021494Sopenharmony_ci  if (generate_simulator_code_) {
462b8021494Sopenharmony_ci    PushRegister(reg4);
463b8021494Sopenharmony_ci    PushRegister(reg3);
464b8021494Sopenharmony_ci    PushRegister(reg2);
465b8021494Sopenharmony_ci    PushRegister(reg1);
466b8021494Sopenharmony_ci    Push(RegisterList(r0, r1));
467b8021494Sopenharmony_ci#ifndef PANDA_BUILD
468b8021494Sopenharmony_ci    StringLiteral* format_literal =
469b8021494Sopenharmony_ci        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
470b8021494Sopenharmony_ci#else
471b8021494Sopenharmony_ci    StringLiteral* format_literal = allocator_.New<StringLiteral>(
472b8021494Sopenharmony_ci        allocator_, format, RawLiteral::kDeletedOnPlacementByPool);
473b8021494Sopenharmony_ci#endif
474b8021494Sopenharmony_ci
475b8021494Sopenharmony_ci    Adr(r0, format_literal);
476b8021494Sopenharmony_ci    uint32_t args = (reg4.GetType() << 12) | (reg3.GetType() << 8) |
477b8021494Sopenharmony_ci                    (reg2.GetType() << 4) | reg1.GetType();
478b8021494Sopenharmony_ci    Mov(r1, args);
479b8021494Sopenharmony_ci    Hvc(kPrintfCode);
480b8021494Sopenharmony_ci    Pop(RegisterList(r0, r1));
481b8021494Sopenharmony_ci    int size = reg4.GetRegSizeInBytes() + reg3.GetRegSizeInBytes() +
482b8021494Sopenharmony_ci               reg2.GetRegSizeInBytes() + reg1.GetRegSizeInBytes();
483b8021494Sopenharmony_ci    Drop(size);
484b8021494Sopenharmony_ci  } else {
485b8021494Sopenharmony_ci    // Generate on a native platform => 32 bit environment.
486b8021494Sopenharmony_ci    // Preserve core registers r0-r3, r12, r14
487b8021494Sopenharmony_ci    const uint32_t saved_registers_mask =
488b8021494Sopenharmony_ci        kCallerSavedRegistersMask | (1 << r5.GetCode());
489b8021494Sopenharmony_ci    Push(RegisterList(saved_registers_mask));
490b8021494Sopenharmony_ci    // Push VFP registers.
491b8021494Sopenharmony_ci    Vpush(Untyped64, DRegisterList(d0, 8));
492b8021494Sopenharmony_ci    if (Has32DRegs()) Vpush(Untyped64, DRegisterList(d16, 16));
493b8021494Sopenharmony_ci    // Search one register which has been saved and which doesn't need to be
494b8021494Sopenharmony_ci    // printed.
495b8021494Sopenharmony_ci    RegisterList available_registers(kCallerSavedRegistersMask);
496b8021494Sopenharmony_ci    if (reg1.GetType() == CPURegister::kRRegister) {
497b8021494Sopenharmony_ci      available_registers.Remove(Register(reg1.GetCode()));
498b8021494Sopenharmony_ci    }
499b8021494Sopenharmony_ci    if (reg2.GetType() == CPURegister::kRRegister) {
500b8021494Sopenharmony_ci      available_registers.Remove(Register(reg2.GetCode()));
501b8021494Sopenharmony_ci    }
502b8021494Sopenharmony_ci    if (reg3.GetType() == CPURegister::kRRegister) {
503b8021494Sopenharmony_ci      available_registers.Remove(Register(reg3.GetCode()));
504b8021494Sopenharmony_ci    }
505b8021494Sopenharmony_ci    if (reg4.GetType() == CPURegister::kRRegister) {
506b8021494Sopenharmony_ci      available_registers.Remove(Register(reg4.GetCode()));
507b8021494Sopenharmony_ci    }
508b8021494Sopenharmony_ci    Register tmp = available_registers.GetFirstAvailableRegister();
509b8021494Sopenharmony_ci    VIXL_ASSERT(tmp.GetType() == CPURegister::kRRegister);
510b8021494Sopenharmony_ci    // Push the flags.
511b8021494Sopenharmony_ci    Mrs(tmp, APSR);
512b8021494Sopenharmony_ci    Push(tmp);
513b8021494Sopenharmony_ci    Vmrs(RegisterOrAPSR_nzcv(tmp.GetCode()), FPSCR);
514b8021494Sopenharmony_ci    Push(tmp);
515b8021494Sopenharmony_ci    // Push the registers to print on the stack.
516b8021494Sopenharmony_ci    PushRegister(reg4);
517b8021494Sopenharmony_ci    PushRegister(reg3);
518b8021494Sopenharmony_ci    PushRegister(reg2);
519b8021494Sopenharmony_ci    PushRegister(reg1);
520b8021494Sopenharmony_ci    int core_count = 1;
521b8021494Sopenharmony_ci    int vfp_count = 0;
522b8021494Sopenharmony_ci    uint32_t printf_type = 0;
523b8021494Sopenharmony_ci    // Pop the registers to print and store them into r1-r3 and/or d0-d3.
524b8021494Sopenharmony_ci    // Reg4 may stay into the stack if all the register to print are core
525b8021494Sopenharmony_ci    // registers.
526b8021494Sopenharmony_ci    PreparePrintfArgument(reg1, &core_count, &vfp_count, &printf_type);
527b8021494Sopenharmony_ci    PreparePrintfArgument(reg2, &core_count, &vfp_count, &printf_type);
528b8021494Sopenharmony_ci    PreparePrintfArgument(reg3, &core_count, &vfp_count, &printf_type);
529b8021494Sopenharmony_ci    PreparePrintfArgument(reg4, &core_count, &vfp_count, &printf_type);
530b8021494Sopenharmony_ci    // Ensure that the stack is aligned on 8 bytes.
531b8021494Sopenharmony_ci    And(r5, sp, 0x7);
532b8021494Sopenharmony_ci    if (core_count == 5) {
533b8021494Sopenharmony_ci      // One 32 bit argument (reg4) has been left on the stack =>  align the
534b8021494Sopenharmony_ci      // stack
535b8021494Sopenharmony_ci      // before the argument.
536b8021494Sopenharmony_ci      Pop(r0);
537b8021494Sopenharmony_ci      Sub(sp, sp, r5);
538b8021494Sopenharmony_ci      Push(r0);
539b8021494Sopenharmony_ci    } else {
540b8021494Sopenharmony_ci      Sub(sp, sp, r5);
541b8021494Sopenharmony_ci    }
542b8021494Sopenharmony_ci    // Select the right trampoline depending on the arguments.
543b8021494Sopenharmony_ci    uintptr_t address;
544b8021494Sopenharmony_ci    switch (printf_type) {
545b8021494Sopenharmony_ci      case 0:
546b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
547b8021494Sopenharmony_ci        break;
548b8021494Sopenharmony_ci      case 1:
549b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRR);
550b8021494Sopenharmony_ci        break;
551b8021494Sopenharmony_ci      case 2:
552b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRR);
553b8021494Sopenharmony_ci        break;
554b8021494Sopenharmony_ci      case 3:
555b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRR);
556b8021494Sopenharmony_ci        break;
557b8021494Sopenharmony_ci      case 4:
558b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDR);
559b8021494Sopenharmony_ci        break;
560b8021494Sopenharmony_ci      case 5:
561b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDR);
562b8021494Sopenharmony_ci        break;
563b8021494Sopenharmony_ci      case 6:
564b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDR);
565b8021494Sopenharmony_ci        break;
566b8021494Sopenharmony_ci      case 7:
567b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDR);
568b8021494Sopenharmony_ci        break;
569b8021494Sopenharmony_ci      case 8:
570b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRD);
571b8021494Sopenharmony_ci        break;
572b8021494Sopenharmony_ci      case 9:
573b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRD);
574b8021494Sopenharmony_ci        break;
575b8021494Sopenharmony_ci      case 10:
576b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRD);
577b8021494Sopenharmony_ci        break;
578b8021494Sopenharmony_ci      case 11:
579b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRD);
580b8021494Sopenharmony_ci        break;
581b8021494Sopenharmony_ci      case 12:
582b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDD);
583b8021494Sopenharmony_ci        break;
584b8021494Sopenharmony_ci      case 13:
585b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDD);
586b8021494Sopenharmony_ci        break;
587b8021494Sopenharmony_ci      case 14:
588b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDD);
589b8021494Sopenharmony_ci        break;
590b8021494Sopenharmony_ci      case 15:
591b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDD);
592b8021494Sopenharmony_ci        break;
593b8021494Sopenharmony_ci      default:
594b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
595b8021494Sopenharmony_ci        address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
596b8021494Sopenharmony_ci        break;
597b8021494Sopenharmony_ci    }
598b8021494Sopenharmony_ci#ifndef PANDA_BUILD
599b8021494Sopenharmony_ci    StringLiteral* format_literal =
600b8021494Sopenharmony_ci        new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
601b8021494Sopenharmony_ci#else
602b8021494Sopenharmony_ci    StringLiteral* format_literal = allocator_.New<StringLiteral>(
603b8021494Sopenharmony_ci        allocator_, format, RawLiteral::kDeletedOnPlacementByPool);
604b8021494Sopenharmony_ci#endif
605b8021494Sopenharmony_ci    Adr(r0, format_literal);
606b8021494Sopenharmony_ci    Mov(ip, Operand::From(address));
607b8021494Sopenharmony_ci    Blx(ip);
608b8021494Sopenharmony_ci    // If register reg4 was left on the stack => skip it.
609b8021494Sopenharmony_ci    if (core_count == 5) Drop(kRegSizeInBytes);
610b8021494Sopenharmony_ci    // Restore the stack as it was before alignment.
611b8021494Sopenharmony_ci    Add(sp, sp, r5);
612b8021494Sopenharmony_ci    // Restore the flags.
613b8021494Sopenharmony_ci    Pop(tmp);
614b8021494Sopenharmony_ci    Vmsr(FPSCR, tmp);
615b8021494Sopenharmony_ci    Pop(tmp);
616b8021494Sopenharmony_ci    Msr(APSR_nzcvqg, tmp);
617b8021494Sopenharmony_ci    // Restore the registers.
618b8021494Sopenharmony_ci    if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
619b8021494Sopenharmony_ci    Vpop(Untyped64, DRegisterList(d0, 8));
620b8021494Sopenharmony_ci    Pop(RegisterList(saved_registers_mask));
621b8021494Sopenharmony_ci  }
622b8021494Sopenharmony_ci}
623b8021494Sopenharmony_ci
624b8021494Sopenharmony_ci
625b8021494Sopenharmony_civoid MacroAssembler::PushRegister(CPURegister reg) {
626b8021494Sopenharmony_ci  switch (reg.GetType()) {
627b8021494Sopenharmony_ci    case CPURegister::kNoRegister:
628b8021494Sopenharmony_ci      break;
629b8021494Sopenharmony_ci    case CPURegister::kRRegister:
630b8021494Sopenharmony_ci      Push(Register(reg.GetCode()));
631b8021494Sopenharmony_ci      break;
632b8021494Sopenharmony_ci    case CPURegister::kSRegister:
633b8021494Sopenharmony_ci      Vpush(Untyped32, SRegisterList(SRegister(reg.GetCode())));
634b8021494Sopenharmony_ci      break;
635b8021494Sopenharmony_ci    case CPURegister::kDRegister:
636b8021494Sopenharmony_ci      Vpush(Untyped64, DRegisterList(DRegister(reg.GetCode())));
637b8021494Sopenharmony_ci      break;
638b8021494Sopenharmony_ci    case CPURegister::kQRegister:
639b8021494Sopenharmony_ci      VIXL_UNIMPLEMENTED();
640b8021494Sopenharmony_ci      break;
641b8021494Sopenharmony_ci  }
642b8021494Sopenharmony_ci}
643b8021494Sopenharmony_ci
644b8021494Sopenharmony_ci
645b8021494Sopenharmony_civoid MacroAssembler::PreparePrintfArgument(CPURegister reg,
646b8021494Sopenharmony_ci                                           int* core_count,
647b8021494Sopenharmony_ci                                           int* vfp_count,
648b8021494Sopenharmony_ci                                           uint32_t* printf_type) {
649b8021494Sopenharmony_ci  switch (reg.GetType()) {
650b8021494Sopenharmony_ci    case CPURegister::kNoRegister:
651b8021494Sopenharmony_ci      break;
652b8021494Sopenharmony_ci    case CPURegister::kRRegister:
653b8021494Sopenharmony_ci      VIXL_ASSERT(*core_count <= 4);
654b8021494Sopenharmony_ci      if (*core_count < 4) Pop(Register(*core_count));
655b8021494Sopenharmony_ci      *core_count += 1;
656b8021494Sopenharmony_ci      break;
657b8021494Sopenharmony_ci    case CPURegister::kSRegister:
658b8021494Sopenharmony_ci      VIXL_ASSERT(*vfp_count < 4);
659b8021494Sopenharmony_ci      *printf_type |= 1 << (*core_count + *vfp_count - 1);
660b8021494Sopenharmony_ci      Vpop(Untyped32, SRegisterList(SRegister(*vfp_count * 2)));
661b8021494Sopenharmony_ci      Vcvt(F64, F32, DRegister(*vfp_count), SRegister(*vfp_count * 2));
662b8021494Sopenharmony_ci      *vfp_count += 1;
663b8021494Sopenharmony_ci      break;
664b8021494Sopenharmony_ci    case CPURegister::kDRegister:
665b8021494Sopenharmony_ci      VIXL_ASSERT(*vfp_count < 4);
666b8021494Sopenharmony_ci      *printf_type |= 1 << (*core_count + *vfp_count - 1);
667b8021494Sopenharmony_ci      Vpop(Untyped64, DRegisterList(DRegister(*vfp_count)));
668b8021494Sopenharmony_ci      *vfp_count += 1;
669b8021494Sopenharmony_ci      break;
670b8021494Sopenharmony_ci    case CPURegister::kQRegister:
671b8021494Sopenharmony_ci      VIXL_UNIMPLEMENTED();
672b8021494Sopenharmony_ci      break;
673b8021494Sopenharmony_ci  }
674b8021494Sopenharmony_ci}
675b8021494Sopenharmony_ci
676b8021494Sopenharmony_ci
677b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
678b8021494Sopenharmony_ci                              InstructionCondROp instruction,
679b8021494Sopenharmony_ci                              Condition cond,
680b8021494Sopenharmony_ci                              Register rn,
681b8021494Sopenharmony_ci                              const Operand& operand) {
682b8021494Sopenharmony_ci  VIXL_ASSERT((type == kMovt) || (type == kSxtb16) || (type == kTeq) ||
683b8021494Sopenharmony_ci              (type == kUxtb16));
684b8021494Sopenharmony_ci
685b8021494Sopenharmony_ci  if (type == kMovt) {
686b8021494Sopenharmony_ci    VIXL_ABORT_WITH_MSG("`Movt` expects a 16-bit immediate.\n");
687b8021494Sopenharmony_ci  }
688b8021494Sopenharmony_ci
689b8021494Sopenharmony_ci  // This delegate only supports teq with immediates.
690b8021494Sopenharmony_ci  CONTEXT_SCOPE;
691b8021494Sopenharmony_ci  if ((type == kTeq) && operand.IsImmediate()) {
692b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
693b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
694b8021494Sopenharmony_ci    HandleOutOfBoundsImmediate(cond, scratch, operand.GetImmediate());
695b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
696b8021494Sopenharmony_ci    teq(cond, rn, scratch);
697b8021494Sopenharmony_ci    return;
698b8021494Sopenharmony_ci  }
699b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, rn, operand);
700b8021494Sopenharmony_ci}
701b8021494Sopenharmony_ci
702b8021494Sopenharmony_ci
703b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
704b8021494Sopenharmony_ci                              InstructionCondSizeROp instruction,
705b8021494Sopenharmony_ci                              Condition cond,
706b8021494Sopenharmony_ci                              EncodingSize size,
707b8021494Sopenharmony_ci                              Register rn,
708b8021494Sopenharmony_ci                              const Operand& operand) {
709b8021494Sopenharmony_ci  CONTEXT_SCOPE;
710b8021494Sopenharmony_ci  VIXL_ASSERT(size.IsBest());
711b8021494Sopenharmony_ci  VIXL_ASSERT((type == kCmn) || (type == kCmp) || (type == kMov) ||
712b8021494Sopenharmony_ci              (type == kMovs) || (type == kMvn) || (type == kMvns) ||
713b8021494Sopenharmony_ci              (type == kSxtb) || (type == kSxth) || (type == kTst) ||
714b8021494Sopenharmony_ci              (type == kUxtb) || (type == kUxth));
715b8021494Sopenharmony_ci  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
716b8021494Sopenharmony_ci    VIXL_ASSERT((type != kMov) || (type != kMovs));
717b8021494Sopenharmony_ci    InstructionCondRROp shiftop = NULL;
718b8021494Sopenharmony_ci    switch (operand.GetShift().GetType()) {
719b8021494Sopenharmony_ci      case LSL:
720b8021494Sopenharmony_ci        shiftop = &Assembler::lsl;
721b8021494Sopenharmony_ci        break;
722b8021494Sopenharmony_ci      case LSR:
723b8021494Sopenharmony_ci        shiftop = &Assembler::lsr;
724b8021494Sopenharmony_ci        break;
725b8021494Sopenharmony_ci      case ASR:
726b8021494Sopenharmony_ci        shiftop = &Assembler::asr;
727b8021494Sopenharmony_ci        break;
728b8021494Sopenharmony_ci      case RRX:
729b8021494Sopenharmony_ci        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
730b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
731b8021494Sopenharmony_ci        break;
732b8021494Sopenharmony_ci      case ROR:
733b8021494Sopenharmony_ci        shiftop = &Assembler::ror;
734b8021494Sopenharmony_ci        break;
735b8021494Sopenharmony_ci      default:
736b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
737b8021494Sopenharmony_ci    }
738b8021494Sopenharmony_ci    if (shiftop != NULL) {
739b8021494Sopenharmony_ci      UseScratchRegisterScope temps(this);
740b8021494Sopenharmony_ci      Register scratch = temps.Acquire();
741b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
742b8021494Sopenharmony_ci      (this->*shiftop)(cond,
743b8021494Sopenharmony_ci                       scratch,
744b8021494Sopenharmony_ci                       operand.GetBaseRegister(),
745b8021494Sopenharmony_ci                       operand.GetShiftRegister());
746b8021494Sopenharmony_ci      (this->*instruction)(cond, size, rn, scratch);
747b8021494Sopenharmony_ci      return;
748b8021494Sopenharmony_ci    }
749b8021494Sopenharmony_ci  }
750b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
751b8021494Sopenharmony_ci    uint32_t imm = operand.GetImmediate();
752b8021494Sopenharmony_ci    switch (type) {
753b8021494Sopenharmony_ci      case kMov:
754b8021494Sopenharmony_ci      case kMovs:
755b8021494Sopenharmony_ci        if (!rn.IsPC()) {
756b8021494Sopenharmony_ci          // Immediate is too large, but not using PC, so handle with mov{t}.
757b8021494Sopenharmony_ci          HandleOutOfBoundsImmediate(cond, rn, imm);
758b8021494Sopenharmony_ci          if (type == kMovs) {
759b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
760b8021494Sopenharmony_ci            tst(cond, rn, rn);
761b8021494Sopenharmony_ci          }
762b8021494Sopenharmony_ci          return;
763b8021494Sopenharmony_ci        } else if (type == kMov) {
764b8021494Sopenharmony_ci          VIXL_ASSERT(IsUsingA32() || cond.Is(al));
765b8021494Sopenharmony_ci          // Immediate is too large and using PC, so handle using a temporary
766b8021494Sopenharmony_ci          // register.
767b8021494Sopenharmony_ci          UseScratchRegisterScope temps(this);
768b8021494Sopenharmony_ci          Register scratch = temps.Acquire();
769b8021494Sopenharmony_ci          HandleOutOfBoundsImmediate(al, scratch, imm);
770b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
771b8021494Sopenharmony_ci          bx(cond, scratch);
772b8021494Sopenharmony_ci          return;
773b8021494Sopenharmony_ci        }
774b8021494Sopenharmony_ci        break;
775b8021494Sopenharmony_ci      case kCmn:
776b8021494Sopenharmony_ci      case kCmp:
777b8021494Sopenharmony_ci        if (IsUsingA32() || !rn.IsPC()) {
778b8021494Sopenharmony_ci          UseScratchRegisterScope temps(this);
779b8021494Sopenharmony_ci          Register scratch = temps.Acquire();
780b8021494Sopenharmony_ci          HandleOutOfBoundsImmediate(cond, scratch, imm);
781b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
782b8021494Sopenharmony_ci          (this->*instruction)(cond, size, rn, scratch);
783b8021494Sopenharmony_ci          return;
784b8021494Sopenharmony_ci        }
785b8021494Sopenharmony_ci        break;
786b8021494Sopenharmony_ci      case kMvn:
787b8021494Sopenharmony_ci      case kMvns:
788b8021494Sopenharmony_ci        if (!rn.IsPC()) {
789b8021494Sopenharmony_ci          UseScratchRegisterScope temps(this);
790b8021494Sopenharmony_ci          Register scratch = temps.Acquire();
791b8021494Sopenharmony_ci          HandleOutOfBoundsImmediate(cond, scratch, imm);
792b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
793b8021494Sopenharmony_ci          (this->*instruction)(cond, size, rn, scratch);
794b8021494Sopenharmony_ci          return;
795b8021494Sopenharmony_ci        }
796b8021494Sopenharmony_ci        break;
797b8021494Sopenharmony_ci      case kTst:
798b8021494Sopenharmony_ci        if (IsUsingA32() || !rn.IsPC()) {
799b8021494Sopenharmony_ci          UseScratchRegisterScope temps(this);
800b8021494Sopenharmony_ci          Register scratch = temps.Acquire();
801b8021494Sopenharmony_ci          HandleOutOfBoundsImmediate(cond, scratch, imm);
802b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
803b8021494Sopenharmony_ci          (this->*instruction)(cond, size, rn, scratch);
804b8021494Sopenharmony_ci          return;
805b8021494Sopenharmony_ci        }
806b8021494Sopenharmony_ci        break;
807b8021494Sopenharmony_ci      default:  // kSxtb, Sxth, Uxtb, Uxth
808b8021494Sopenharmony_ci        break;
809b8021494Sopenharmony_ci    }
810b8021494Sopenharmony_ci  }
811b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, size, rn, operand);
812b8021494Sopenharmony_ci}
813b8021494Sopenharmony_ci
814b8021494Sopenharmony_ci
815b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
816b8021494Sopenharmony_ci                              InstructionCondRROp instruction,
817b8021494Sopenharmony_ci                              Condition cond,
818b8021494Sopenharmony_ci                              Register rd,
819b8021494Sopenharmony_ci                              Register rn,
820b8021494Sopenharmony_ci                              const Operand& operand) {
821b8021494Sopenharmony_ci  if ((type == kSxtab) || (type == kSxtab16) || (type == kSxtah) ||
822b8021494Sopenharmony_ci      (type == kUxtab) || (type == kUxtab16) || (type == kUxtah) ||
823b8021494Sopenharmony_ci      (type == kPkhbt) || (type == kPkhtb)) {
824b8021494Sopenharmony_ci    UnimplementedDelegate(type);
825b8021494Sopenharmony_ci    return;
826b8021494Sopenharmony_ci  }
827b8021494Sopenharmony_ci
828b8021494Sopenharmony_ci  // This delegate only handles the following instructions.
829b8021494Sopenharmony_ci  VIXL_ASSERT((type == kOrn) || (type == kOrns) || (type == kRsc) ||
830b8021494Sopenharmony_ci              (type == kRscs));
831b8021494Sopenharmony_ci  CONTEXT_SCOPE;
832b8021494Sopenharmony_ci
833b8021494Sopenharmony_ci  // T32 does not support register shifted register operands, emulate it.
834b8021494Sopenharmony_ci  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
835b8021494Sopenharmony_ci    InstructionCondRROp shiftop = NULL;
836b8021494Sopenharmony_ci    switch (operand.GetShift().GetType()) {
837b8021494Sopenharmony_ci      case LSL:
838b8021494Sopenharmony_ci        shiftop = &Assembler::lsl;
839b8021494Sopenharmony_ci        break;
840b8021494Sopenharmony_ci      case LSR:
841b8021494Sopenharmony_ci        shiftop = &Assembler::lsr;
842b8021494Sopenharmony_ci        break;
843b8021494Sopenharmony_ci      case ASR:
844b8021494Sopenharmony_ci        shiftop = &Assembler::asr;
845b8021494Sopenharmony_ci        break;
846b8021494Sopenharmony_ci      case RRX:
847b8021494Sopenharmony_ci        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
848b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
849b8021494Sopenharmony_ci        break;
850b8021494Sopenharmony_ci      case ROR:
851b8021494Sopenharmony_ci        shiftop = &Assembler::ror;
852b8021494Sopenharmony_ci        break;
853b8021494Sopenharmony_ci      default:
854b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
855b8021494Sopenharmony_ci    }
856b8021494Sopenharmony_ci    if (shiftop != NULL) {
857b8021494Sopenharmony_ci      UseScratchRegisterScope temps(this);
858b8021494Sopenharmony_ci      Register rm = operand.GetBaseRegister();
859b8021494Sopenharmony_ci      Register rs = operand.GetShiftRegister();
860b8021494Sopenharmony_ci      // Try to use rd as a scratch register. We can do this if it aliases rs or
861b8021494Sopenharmony_ci      // rm (because we read them in the first instruction), but not rn.
862b8021494Sopenharmony_ci      if (!rd.Is(rn)) temps.Include(rd);
863b8021494Sopenharmony_ci      Register scratch = temps.Acquire();
864b8021494Sopenharmony_ci      // TODO: The scope length was measured empirically. We should analyse the
865b8021494Sopenharmony_ci      // worst-case size and add targetted tests.
866b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
867b8021494Sopenharmony_ci      (this->*shiftop)(cond, scratch, rm, rs);
868b8021494Sopenharmony_ci      (this->*instruction)(cond, rd, rn, scratch);
869b8021494Sopenharmony_ci      return;
870b8021494Sopenharmony_ci    }
871b8021494Sopenharmony_ci  }
872b8021494Sopenharmony_ci
873b8021494Sopenharmony_ci  // T32 does not have a Rsc instruction, negate the lhs input and turn it into
874b8021494Sopenharmony_ci  // an Adc. Adc and Rsc are equivalent using a bitwise NOT:
875b8021494Sopenharmony_ci  //   adc rd, rn, operand <-> rsc rd, NOT(rn), operand
876b8021494Sopenharmony_ci  if (IsUsingT32() && ((type == kRsc) || (type == kRscs))) {
877b8021494Sopenharmony_ci    // The RegisterShiftRegister case should have been handled above.
878b8021494Sopenharmony_ci    VIXL_ASSERT(!operand.IsRegisterShiftedRegister());
879b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
880b8021494Sopenharmony_ci    // Try to use rd as a scratch register. We can do this if it aliases rn
881b8021494Sopenharmony_ci    // (because we read it in the first instruction), but not rm.
882b8021494Sopenharmony_ci    temps.Include(rd);
883b8021494Sopenharmony_ci    temps.Exclude(operand);
884b8021494Sopenharmony_ci    Register negated_rn = temps.Acquire();
885b8021494Sopenharmony_ci    {
886b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
887b8021494Sopenharmony_ci      mvn(cond, negated_rn, rn);
888b8021494Sopenharmony_ci    }
889b8021494Sopenharmony_ci    if (type == kRsc) {
890b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
891b8021494Sopenharmony_ci      adc(cond, rd, negated_rn, operand);
892b8021494Sopenharmony_ci      return;
893b8021494Sopenharmony_ci    }
894b8021494Sopenharmony_ci    // TODO: We shouldn't have to specify how much space the next instruction
895b8021494Sopenharmony_ci    // needs.
896b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
897b8021494Sopenharmony_ci    adcs(cond, rd, negated_rn, operand);
898b8021494Sopenharmony_ci    return;
899b8021494Sopenharmony_ci  }
900b8021494Sopenharmony_ci
901b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
902b8021494Sopenharmony_ci    // If the immediate can be encoded when inverted, turn Orn into Orr.
903b8021494Sopenharmony_ci    // Otherwise rely on HandleOutOfBoundsImmediate to generate a series of
904b8021494Sopenharmony_ci    // mov.
905b8021494Sopenharmony_ci    int32_t imm = operand.GetSignedImmediate();
906b8021494Sopenharmony_ci    if (((type == kOrn) || (type == kOrns)) && IsModifiedImmediate(~imm)) {
907b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
908b8021494Sopenharmony_ci      switch (type) {
909b8021494Sopenharmony_ci        case kOrn:
910b8021494Sopenharmony_ci          orr(cond, rd, rn, ~imm);
911b8021494Sopenharmony_ci          return;
912b8021494Sopenharmony_ci        case kOrns:
913b8021494Sopenharmony_ci          orrs(cond, rd, rn, ~imm);
914b8021494Sopenharmony_ci          return;
915b8021494Sopenharmony_ci        default:
916b8021494Sopenharmony_ci          VIXL_UNREACHABLE();
917b8021494Sopenharmony_ci          break;
918b8021494Sopenharmony_ci      }
919b8021494Sopenharmony_ci    }
920b8021494Sopenharmony_ci  }
921b8021494Sopenharmony_ci
922b8021494Sopenharmony_ci  // A32 does not have a Orn instruction, negate the rhs input and turn it into
923b8021494Sopenharmony_ci  // a Orr.
924b8021494Sopenharmony_ci  if (IsUsingA32() && ((type == kOrn) || (type == kOrns))) {
925b8021494Sopenharmony_ci    // TODO: orn r0, r1, imm -> orr r0, r1, neg(imm) if doable
926b8021494Sopenharmony_ci    //  mvn r0, r2
927b8021494Sopenharmony_ci    //  orr r0, r1, r0
928b8021494Sopenharmony_ci    Register scratch;
929b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
930b8021494Sopenharmony_ci    // Try to use rd as a scratch register. We can do this if it aliases rs or
931b8021494Sopenharmony_ci    // rm (because we read them in the first instruction), but not rn.
932b8021494Sopenharmony_ci    if (!rd.Is(rn)) temps.Include(rd);
933b8021494Sopenharmony_ci    scratch = temps.Acquire();
934b8021494Sopenharmony_ci    {
935b8021494Sopenharmony_ci      // TODO: We shouldn't have to specify how much space the next instruction
936b8021494Sopenharmony_ci      // needs.
937b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
938b8021494Sopenharmony_ci      mvn(cond, scratch, operand);
939b8021494Sopenharmony_ci    }
940b8021494Sopenharmony_ci    if (type == kOrns) {
941b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
942b8021494Sopenharmony_ci      orrs(cond, rd, rn, scratch);
943b8021494Sopenharmony_ci      return;
944b8021494Sopenharmony_ci    }
945b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
946b8021494Sopenharmony_ci    orr(cond, rd, rn, scratch);
947b8021494Sopenharmony_ci    return;
948b8021494Sopenharmony_ci  }
949b8021494Sopenharmony_ci
950b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
951b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
952b8021494Sopenharmony_ci    // Allow using the destination as a scratch register if possible.
953b8021494Sopenharmony_ci    if (!rd.Is(rn)) temps.Include(rd);
954b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
955b8021494Sopenharmony_ci    int32_t imm = operand.GetSignedImmediate();
956b8021494Sopenharmony_ci    HandleOutOfBoundsImmediate(cond, scratch, imm);
957b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
958b8021494Sopenharmony_ci    (this->*instruction)(cond, rd, rn, scratch);
959b8021494Sopenharmony_ci    return;
960b8021494Sopenharmony_ci  }
961b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, rd, rn, operand);
962b8021494Sopenharmony_ci}
963b8021494Sopenharmony_ci
964b8021494Sopenharmony_ci
965b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
966b8021494Sopenharmony_ci                              InstructionCondSizeRL instruction,
967b8021494Sopenharmony_ci                              Condition cond,
968b8021494Sopenharmony_ci                              EncodingSize size,
969b8021494Sopenharmony_ci                              Register rd,
970b8021494Sopenharmony_ci                              Location* location) {
971b8021494Sopenharmony_ci  VIXL_ASSERT((type == kLdr) || (type == kAdr));
972b8021494Sopenharmony_ci
973b8021494Sopenharmony_ci  CONTEXT_SCOPE;
974b8021494Sopenharmony_ci  VIXL_ASSERT(size.IsBest());
975b8021494Sopenharmony_ci
976b8021494Sopenharmony_ci  if ((type == kLdr) && location->IsBound()) {
977b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
978b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
979b8021494Sopenharmony_ci    temps.Include(rd);
980b8021494Sopenharmony_ci    uint32_t mask = GetOffsetMask(type, Offset);
981b8021494Sopenharmony_ci    ldr(rd, MemOperandComputationHelper(cond, temps.Acquire(), location, mask));
982b8021494Sopenharmony_ci    return;
983b8021494Sopenharmony_ci  }
984b8021494Sopenharmony_ci
985b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, size, rd, location);
986b8021494Sopenharmony_ci}
987b8021494Sopenharmony_ci
988b8021494Sopenharmony_ci
989b8021494Sopenharmony_cibool MacroAssembler::GenerateSplitInstruction(
990b8021494Sopenharmony_ci    InstructionCondSizeRROp instruction,
991b8021494Sopenharmony_ci    Condition cond,
992b8021494Sopenharmony_ci    Register rd,
993b8021494Sopenharmony_ci    Register rn,
994b8021494Sopenharmony_ci    uint32_t imm,
995b8021494Sopenharmony_ci    uint32_t mask) {
996b8021494Sopenharmony_ci  uint32_t high = imm & ~mask;
997b8021494Sopenharmony_ci  if (!IsModifiedImmediate(high) && !rn.IsPC()) return false;
998b8021494Sopenharmony_ci  // If high is a modified immediate, we can perform the operation with
999b8021494Sopenharmony_ci  // only 2 instructions.
1000b8021494Sopenharmony_ci  // Else, if rn is PC, we want to avoid moving PC into a temporary.
1001b8021494Sopenharmony_ci  // Therefore, we also use the pattern even if the second call may
1002b8021494Sopenharmony_ci  // generate 3 instructions.
1003b8021494Sopenharmony_ci  uint32_t low = imm & mask;
1004b8021494Sopenharmony_ci  CodeBufferCheckScope scope(this,
1005b8021494Sopenharmony_ci                             (rn.IsPC() ? 4 : 2) * kMaxInstructionSizeInBytes);
1006b8021494Sopenharmony_ci  (this->*instruction)(cond, Best, rd, rn, low);
1007b8021494Sopenharmony_ci  (this->*instruction)(cond, Best, rd, rd, high);
1008b8021494Sopenharmony_ci  return true;
1009b8021494Sopenharmony_ci}
1010b8021494Sopenharmony_ci
1011b8021494Sopenharmony_ci
1012b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1013b8021494Sopenharmony_ci                              InstructionCondSizeRROp instruction,
1014b8021494Sopenharmony_ci                              Condition cond,
1015b8021494Sopenharmony_ci                              EncodingSize size,
1016b8021494Sopenharmony_ci                              Register rd,
1017b8021494Sopenharmony_ci                              Register rn,
1018b8021494Sopenharmony_ci                              const Operand& operand) {
1019b8021494Sopenharmony_ci  VIXL_ASSERT(
1020b8021494Sopenharmony_ci      (type == kAdc) || (type == kAdcs) || (type == kAdd) || (type == kAdds) ||
1021b8021494Sopenharmony_ci      (type == kAnd) || (type == kAnds) || (type == kAsr) || (type == kAsrs) ||
1022b8021494Sopenharmony_ci      (type == kBic) || (type == kBics) || (type == kEor) || (type == kEors) ||
1023b8021494Sopenharmony_ci      (type == kLsl) || (type == kLsls) || (type == kLsr) || (type == kLsrs) ||
1024b8021494Sopenharmony_ci      (type == kOrr) || (type == kOrrs) || (type == kRor) || (type == kRors) ||
1025b8021494Sopenharmony_ci      (type == kRsb) || (type == kRsbs) || (type == kSbc) || (type == kSbcs) ||
1026b8021494Sopenharmony_ci      (type == kSub) || (type == kSubs));
1027b8021494Sopenharmony_ci
1028b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1029b8021494Sopenharmony_ci  VIXL_ASSERT(size.IsBest());
1030b8021494Sopenharmony_ci  if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
1031b8021494Sopenharmony_ci    InstructionCondRROp shiftop = NULL;
1032b8021494Sopenharmony_ci    switch (operand.GetShift().GetType()) {
1033b8021494Sopenharmony_ci      case LSL:
1034b8021494Sopenharmony_ci        shiftop = &Assembler::lsl;
1035b8021494Sopenharmony_ci        break;
1036b8021494Sopenharmony_ci      case LSR:
1037b8021494Sopenharmony_ci        shiftop = &Assembler::lsr;
1038b8021494Sopenharmony_ci        break;
1039b8021494Sopenharmony_ci      case ASR:
1040b8021494Sopenharmony_ci        shiftop = &Assembler::asr;
1041b8021494Sopenharmony_ci        break;
1042b8021494Sopenharmony_ci      case RRX:
1043b8021494Sopenharmony_ci        // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1044b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
1045b8021494Sopenharmony_ci        break;
1046b8021494Sopenharmony_ci      case ROR:
1047b8021494Sopenharmony_ci        shiftop = &Assembler::ror;
1048b8021494Sopenharmony_ci        break;
1049b8021494Sopenharmony_ci      default:
1050b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
1051b8021494Sopenharmony_ci    }
1052b8021494Sopenharmony_ci    if (shiftop != NULL) {
1053b8021494Sopenharmony_ci      UseScratchRegisterScope temps(this);
1054b8021494Sopenharmony_ci      Register rm = operand.GetBaseRegister();
1055b8021494Sopenharmony_ci      Register rs = operand.GetShiftRegister();
1056b8021494Sopenharmony_ci      // Try to use rd as a scratch register. We can do this if it aliases rs or
1057b8021494Sopenharmony_ci      // rm (because we read them in the first instruction), but not rn.
1058b8021494Sopenharmony_ci      if (!rd.Is(rn)) temps.Include(rd);
1059b8021494Sopenharmony_ci      Register scratch = temps.Acquire();
1060b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1061b8021494Sopenharmony_ci      (this->*shiftop)(cond, scratch, rm, rs);
1062b8021494Sopenharmony_ci      (this->*instruction)(cond, size, rd, rn, scratch);
1063b8021494Sopenharmony_ci      return;
1064b8021494Sopenharmony_ci    }
1065b8021494Sopenharmony_ci  }
1066b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
1067b8021494Sopenharmony_ci    int32_t imm = operand.GetSignedImmediate();
1068b8021494Sopenharmony_ci    if (ImmediateT32::IsImmediateT32(~imm)) {
1069b8021494Sopenharmony_ci      if (IsUsingT32()) {
1070b8021494Sopenharmony_ci        switch (type) {
1071b8021494Sopenharmony_ci          case kOrr:
1072b8021494Sopenharmony_ci            orn(cond, rd, rn, ~imm);
1073b8021494Sopenharmony_ci            return;
1074b8021494Sopenharmony_ci          case kOrrs:
1075b8021494Sopenharmony_ci            orns(cond, rd, rn, ~imm);
1076b8021494Sopenharmony_ci            return;
1077b8021494Sopenharmony_ci          default:
1078b8021494Sopenharmony_ci            break;
1079b8021494Sopenharmony_ci        }
1080b8021494Sopenharmony_ci      }
1081b8021494Sopenharmony_ci    }
1082b8021494Sopenharmony_ci    if (imm < 0) {
1083b8021494Sopenharmony_ci      InstructionCondSizeRROp asmcb = NULL;
1084b8021494Sopenharmony_ci      // Add and sub are equivalent using an arithmetic negation:
1085b8021494Sopenharmony_ci      //   add rd, rn, #imm <-> sub rd, rn, - #imm
1086b8021494Sopenharmony_ci      // Add and sub with carry are equivalent using a bitwise NOT:
1087b8021494Sopenharmony_ci      //   adc rd, rn, #imm <-> sbc rd, rn, NOT #imm
1088b8021494Sopenharmony_ci      switch (type) {
1089b8021494Sopenharmony_ci        case kAdd:
1090b8021494Sopenharmony_ci          asmcb = &Assembler::sub;
1091b8021494Sopenharmony_ci          imm = -imm;
1092b8021494Sopenharmony_ci          break;
1093b8021494Sopenharmony_ci        case kAdds:
1094b8021494Sopenharmony_ci          asmcb = &Assembler::subs;
1095b8021494Sopenharmony_ci          imm = -imm;
1096b8021494Sopenharmony_ci          break;
1097b8021494Sopenharmony_ci        case kSub:
1098b8021494Sopenharmony_ci          asmcb = &Assembler::add;
1099b8021494Sopenharmony_ci          imm = -imm;
1100b8021494Sopenharmony_ci          break;
1101b8021494Sopenharmony_ci        case kSubs:
1102b8021494Sopenharmony_ci          asmcb = &Assembler::adds;
1103b8021494Sopenharmony_ci          imm = -imm;
1104b8021494Sopenharmony_ci          break;
1105b8021494Sopenharmony_ci        case kAdc:
1106b8021494Sopenharmony_ci          asmcb = &Assembler::sbc;
1107b8021494Sopenharmony_ci          imm = ~imm;
1108b8021494Sopenharmony_ci          break;
1109b8021494Sopenharmony_ci        case kAdcs:
1110b8021494Sopenharmony_ci          asmcb = &Assembler::sbcs;
1111b8021494Sopenharmony_ci          imm = ~imm;
1112b8021494Sopenharmony_ci          break;
1113b8021494Sopenharmony_ci        case kSbc:
1114b8021494Sopenharmony_ci          asmcb = &Assembler::adc;
1115b8021494Sopenharmony_ci          imm = ~imm;
1116b8021494Sopenharmony_ci          break;
1117b8021494Sopenharmony_ci        case kSbcs:
1118b8021494Sopenharmony_ci          asmcb = &Assembler::adcs;
1119b8021494Sopenharmony_ci          imm = ~imm;
1120b8021494Sopenharmony_ci          break;
1121b8021494Sopenharmony_ci        default:
1122b8021494Sopenharmony_ci          break;
1123b8021494Sopenharmony_ci      }
1124b8021494Sopenharmony_ci      if (asmcb != NULL) {
1125b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1126b8021494Sopenharmony_ci        (this->*asmcb)(cond, size, rd, rn, Operand(imm));
1127b8021494Sopenharmony_ci        return;
1128b8021494Sopenharmony_ci      }
1129b8021494Sopenharmony_ci    }
1130b8021494Sopenharmony_ci
1131b8021494Sopenharmony_ci    // When rn is PC, only handle negative offsets. The correct way to handle
1132b8021494Sopenharmony_ci    // positive offsets isn't clear; does the user want the offset from the
1133b8021494Sopenharmony_ci    // start of the macro, or from the end (to allow a certain amount of space)?
1134b8021494Sopenharmony_ci    // When type is Add or Sub, imm is always positive (imm < 0 has just been
1135b8021494Sopenharmony_ci    // handled and imm == 0 would have been generated without the need of a
1136b8021494Sopenharmony_ci    // delegate). Therefore, only add to PC is forbidden here.
1137b8021494Sopenharmony_ci    if ((((type == kAdd) && !rn.IsPC()) || (type == kSub)) &&
1138b8021494Sopenharmony_ci        (IsUsingA32() || (!rd.IsPC() && !rn.IsPC()))) {
1139b8021494Sopenharmony_ci      VIXL_ASSERT(imm > 0);
1140b8021494Sopenharmony_ci      // Try to break the constant into two modified immediates.
1141b8021494Sopenharmony_ci      // For T32 also try to break the constant into one imm12 and one modified
1142b8021494Sopenharmony_ci      // immediate. Count the trailing zeroes and get the biggest even value.
1143b8021494Sopenharmony_ci      int trailing_zeroes = CountTrailingZeros(imm) & ~1u;
1144b8021494Sopenharmony_ci      uint32_t mask = ((trailing_zeroes < 4) && IsUsingT32())
1145b8021494Sopenharmony_ci                          ? 0xfff
1146b8021494Sopenharmony_ci                          : (0xff << trailing_zeroes);
1147b8021494Sopenharmony_ci      if (GenerateSplitInstruction(instruction, cond, rd, rn, imm, mask)) {
1148b8021494Sopenharmony_ci        return;
1149b8021494Sopenharmony_ci      }
1150b8021494Sopenharmony_ci      InstructionCondSizeRROp asmcb = NULL;
1151b8021494Sopenharmony_ci      switch (type) {
1152b8021494Sopenharmony_ci        case kAdd:
1153b8021494Sopenharmony_ci          asmcb = &Assembler::sub;
1154b8021494Sopenharmony_ci          break;
1155b8021494Sopenharmony_ci        case kSub:
1156b8021494Sopenharmony_ci          asmcb = &Assembler::add;
1157b8021494Sopenharmony_ci          break;
1158b8021494Sopenharmony_ci        default:
1159b8021494Sopenharmony_ci          VIXL_UNREACHABLE();
1160b8021494Sopenharmony_ci      }
1161b8021494Sopenharmony_ci      if (GenerateSplitInstruction(asmcb, cond, rd, rn, -imm, mask)) {
1162b8021494Sopenharmony_ci        return;
1163b8021494Sopenharmony_ci      }
1164b8021494Sopenharmony_ci    }
1165b8021494Sopenharmony_ci
1166b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
1167b8021494Sopenharmony_ci    // Allow using the destination as a scratch register if possible.
1168b8021494Sopenharmony_ci    if (!rd.Is(rn)) temps.Include(rd);
1169b8021494Sopenharmony_ci    if (rn.IsPC()) {
1170b8021494Sopenharmony_ci      // If we're reading the PC, we need to do it in the first instruction,
1171b8021494Sopenharmony_ci      // otherwise we'll read the wrong value. We rely on this to handle the
1172b8021494Sopenharmony_ci      // long-range PC-relative MemOperands which can result from user-managed
1173b8021494Sopenharmony_ci      // literals.
1174b8021494Sopenharmony_ci
1175b8021494Sopenharmony_ci      // Only handle negative offsets. The correct way to handle positive
1176b8021494Sopenharmony_ci      // offsets isn't clear; does the user want the offset from the start of
1177b8021494Sopenharmony_ci      // the macro, or from the end (to allow a certain amount of space)?
1178b8021494Sopenharmony_ci      bool offset_is_negative_or_zero = (imm <= 0);
1179b8021494Sopenharmony_ci      switch (type) {
1180b8021494Sopenharmony_ci        case kAdd:
1181b8021494Sopenharmony_ci        case kAdds:
1182b8021494Sopenharmony_ci          offset_is_negative_or_zero = (imm <= 0);
1183b8021494Sopenharmony_ci          break;
1184b8021494Sopenharmony_ci        case kSub:
1185b8021494Sopenharmony_ci        case kSubs:
1186b8021494Sopenharmony_ci          offset_is_negative_or_zero = (imm >= 0);
1187b8021494Sopenharmony_ci          break;
1188b8021494Sopenharmony_ci        case kAdc:
1189b8021494Sopenharmony_ci        case kAdcs:
1190b8021494Sopenharmony_ci          offset_is_negative_or_zero = (imm < 0);
1191b8021494Sopenharmony_ci          break;
1192b8021494Sopenharmony_ci        case kSbc:
1193b8021494Sopenharmony_ci        case kSbcs:
1194b8021494Sopenharmony_ci          offset_is_negative_or_zero = (imm > 0);
1195b8021494Sopenharmony_ci          break;
1196b8021494Sopenharmony_ci        default:
1197b8021494Sopenharmony_ci          break;
1198b8021494Sopenharmony_ci      }
1199b8021494Sopenharmony_ci      if (offset_is_negative_or_zero) {
1200b8021494Sopenharmony_ci        {
1201b8021494Sopenharmony_ci          rn = temps.Acquire();
1202b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1203b8021494Sopenharmony_ci          mov(cond, rn, pc);
1204b8021494Sopenharmony_ci        }
1205b8021494Sopenharmony_ci        // Recurse rather than falling through, to try to get the immediate into
1206b8021494Sopenharmony_ci        // a single instruction.
1207b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1208b8021494Sopenharmony_ci        (this->*instruction)(cond, size, rd, rn, operand);
1209b8021494Sopenharmony_ci        return;
1210b8021494Sopenharmony_ci      }
1211b8021494Sopenharmony_ci    } else {
1212b8021494Sopenharmony_ci      Register scratch = temps.Acquire();
1213b8021494Sopenharmony_ci      // TODO: The scope length was measured empirically. We should analyse the
1214b8021494Sopenharmony_ci      // worst-case size and add targetted tests.
1215b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1216b8021494Sopenharmony_ci      mov(cond, scratch, operand.GetImmediate());
1217b8021494Sopenharmony_ci      (this->*instruction)(cond, size, rd, rn, scratch);
1218b8021494Sopenharmony_ci      return;
1219b8021494Sopenharmony_ci    }
1220b8021494Sopenharmony_ci  }
1221b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, size, rd, rn, operand);
1222b8021494Sopenharmony_ci}
1223b8021494Sopenharmony_ci
1224b8021494Sopenharmony_ci
1225b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1226b8021494Sopenharmony_ci                              InstructionRL instruction,
1227b8021494Sopenharmony_ci                              Register rn,
1228b8021494Sopenharmony_ci                              Location* location) {
1229b8021494Sopenharmony_ci  VIXL_ASSERT((type == kCbz) || (type == kCbnz));
1230b8021494Sopenharmony_ci
1231b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1232b8021494Sopenharmony_ci  CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1233b8021494Sopenharmony_ci  if (IsUsingA32()) {
1234b8021494Sopenharmony_ci    if (type == kCbz) {
1235b8021494Sopenharmony_ci      VIXL_ABORT_WITH_MSG("Cbz is only available for T32.\n");
1236b8021494Sopenharmony_ci    } else {
1237b8021494Sopenharmony_ci      VIXL_ABORT_WITH_MSG("Cbnz is only available for T32.\n");
1238b8021494Sopenharmony_ci    }
1239b8021494Sopenharmony_ci  } else if (rn.IsLow()) {
1240b8021494Sopenharmony_ci    switch (type) {
1241b8021494Sopenharmony_ci      case kCbnz: {
1242b8021494Sopenharmony_ci#ifndef PANDA_BUILD
1243b8021494Sopenharmony_ci        Label done;
1244b8021494Sopenharmony_ci#else
1245b8021494Sopenharmony_ci        Label done(allocator_);
1246b8021494Sopenharmony_ci#endif
1247b8021494Sopenharmony_ci        cbz(rn, &done);
1248b8021494Sopenharmony_ci        b(location);
1249b8021494Sopenharmony_ci        Bind(&done);
1250b8021494Sopenharmony_ci        return;
1251b8021494Sopenharmony_ci      }
1252b8021494Sopenharmony_ci      case kCbz: {
1253b8021494Sopenharmony_ci#ifndef PANDA_BUILD
1254b8021494Sopenharmony_ci        Label done;
1255b8021494Sopenharmony_ci#else
1256b8021494Sopenharmony_ci        Label done(allocator_);
1257b8021494Sopenharmony_ci#endif
1258b8021494Sopenharmony_ci        cbnz(rn, &done);
1259b8021494Sopenharmony_ci        b(location);
1260b8021494Sopenharmony_ci        Bind(&done);
1261b8021494Sopenharmony_ci        return;
1262b8021494Sopenharmony_ci      }
1263b8021494Sopenharmony_ci      default:
1264b8021494Sopenharmony_ci        break;
1265b8021494Sopenharmony_ci    }
1266b8021494Sopenharmony_ci  }
1267b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, rn, location);
1268b8021494Sopenharmony_ci}
1269b8021494Sopenharmony_ci
1270b8021494Sopenharmony_ci
1271b8021494Sopenharmony_citemplate <typename T>
1272b8021494Sopenharmony_cistatic inline bool IsI64BitPattern(T imm) {
1273b8021494Sopenharmony_ci  for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
1274b8021494Sopenharmony_ci    if (((imm & mask) != mask) && ((imm & mask) != 0)) return false;
1275b8021494Sopenharmony_ci  }
1276b8021494Sopenharmony_ci  return true;
1277b8021494Sopenharmony_ci}
1278b8021494Sopenharmony_ci
1279b8021494Sopenharmony_ci
1280b8021494Sopenharmony_citemplate <typename T>
1281b8021494Sopenharmony_cistatic inline bool IsI8BitPattern(T imm) {
1282b8021494Sopenharmony_ci  uint8_t imm8 = imm & 0xff;
1283b8021494Sopenharmony_ci  for (unsigned rep = sizeof(T) - 1; rep > 0; rep--) {
1284b8021494Sopenharmony_ci    imm >>= 8;
1285b8021494Sopenharmony_ci    if ((imm & 0xff) != imm8) return false;
1286b8021494Sopenharmony_ci  }
1287b8021494Sopenharmony_ci  return true;
1288b8021494Sopenharmony_ci}
1289b8021494Sopenharmony_ci
1290b8021494Sopenharmony_ci
1291b8021494Sopenharmony_cistatic inline bool CanBeInverted(uint32_t imm32) {
1292b8021494Sopenharmony_ci  uint32_t fill8 = 0;
1293b8021494Sopenharmony_ci
1294b8021494Sopenharmony_ci  if ((imm32 & 0xffffff00) == 0xffffff00) {
1295b8021494Sopenharmony_ci    //    11111111 11111111 11111111 abcdefgh
1296b8021494Sopenharmony_ci    return true;
1297b8021494Sopenharmony_ci  }
1298b8021494Sopenharmony_ci  if (((imm32 & 0xff) == 0) || ((imm32 & 0xff) == 0xff)) {
1299b8021494Sopenharmony_ci    fill8 = imm32 & 0xff;
1300b8021494Sopenharmony_ci    imm32 >>= 8;
1301b8021494Sopenharmony_ci    if ((imm32 >> 8) == 0xffff) {
1302b8021494Sopenharmony_ci      //    11111111 11111111 abcdefgh 00000000
1303b8021494Sopenharmony_ci      // or 11111111 11111111 abcdefgh 11111111
1304b8021494Sopenharmony_ci      return true;
1305b8021494Sopenharmony_ci    }
1306b8021494Sopenharmony_ci    if ((imm32 & 0xff) == fill8) {
1307b8021494Sopenharmony_ci      imm32 >>= 8;
1308b8021494Sopenharmony_ci      if ((imm32 >> 8) == 0xff) {
1309b8021494Sopenharmony_ci        //    11111111 abcdefgh 00000000 00000000
1310b8021494Sopenharmony_ci        // or 11111111 abcdefgh 11111111 11111111
1311b8021494Sopenharmony_ci        return true;
1312b8021494Sopenharmony_ci      }
1313b8021494Sopenharmony_ci      if ((fill8 == 0xff) && ((imm32 & 0xff) == 0xff)) {
1314b8021494Sopenharmony_ci        //    abcdefgh 11111111 11111111 11111111
1315b8021494Sopenharmony_ci        return true;
1316b8021494Sopenharmony_ci      }
1317b8021494Sopenharmony_ci    }
1318b8021494Sopenharmony_ci  }
1319b8021494Sopenharmony_ci  return false;
1320b8021494Sopenharmony_ci}
1321b8021494Sopenharmony_ci
1322b8021494Sopenharmony_ci
1323b8021494Sopenharmony_citemplate <typename RES, typename T>
1324b8021494Sopenharmony_cistatic inline RES replicate(T imm) {
1325b8021494Sopenharmony_ci  VIXL_ASSERT((sizeof(RES) > sizeof(T)) &&
1326b8021494Sopenharmony_ci              (((sizeof(RES) / sizeof(T)) * sizeof(T)) == sizeof(RES)));
1327b8021494Sopenharmony_ci  RES res = imm;
1328b8021494Sopenharmony_ci  for (unsigned i = sizeof(RES) / sizeof(T) - 1; i > 0; i--) {
1329b8021494Sopenharmony_ci    res = (res << (sizeof(T) * 8)) | imm;
1330b8021494Sopenharmony_ci  }
1331b8021494Sopenharmony_ci  return res;
1332b8021494Sopenharmony_ci}
1333b8021494Sopenharmony_ci
1334b8021494Sopenharmony_ci
1335b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1336b8021494Sopenharmony_ci                              InstructionCondDtSSop instruction,
1337b8021494Sopenharmony_ci                              Condition cond,
1338b8021494Sopenharmony_ci                              DataType dt,
1339b8021494Sopenharmony_ci                              SRegister rd,
1340b8021494Sopenharmony_ci                              const SOperand& operand) {
1341b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1342b8021494Sopenharmony_ci  if (type == kVmov) {
1343b8021494Sopenharmony_ci    if (operand.IsImmediate() && dt.Is(F32)) {
1344b8021494Sopenharmony_ci      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1345b8021494Sopenharmony_ci      if (neon_imm.CanConvert<float>()) {
1346b8021494Sopenharmony_ci        // movw ip, imm16
1347b8021494Sopenharmony_ci        // movk ip, imm16
1348b8021494Sopenharmony_ci        // vmov s0, ip
1349b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1350b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
1351b8021494Sopenharmony_ci        float f = neon_imm.GetImmediate<float>();
1352b8021494Sopenharmony_ci        // TODO: The scope length was measured empirically. We should analyse
1353b8021494Sopenharmony_ci        // the
1354b8021494Sopenharmony_ci        // worst-case size and add targetted tests.
1355b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1356b8021494Sopenharmony_ci        mov(cond, scratch, FloatToRawbits(f));
1357b8021494Sopenharmony_ci        vmov(cond, rd, scratch);
1358b8021494Sopenharmony_ci        return;
1359b8021494Sopenharmony_ci      }
1360b8021494Sopenharmony_ci    }
1361b8021494Sopenharmony_ci  }
1362b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1363b8021494Sopenharmony_ci}
1364b8021494Sopenharmony_ci
1365b8021494Sopenharmony_ci
1366b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1367b8021494Sopenharmony_ci                              InstructionCondDtDDop instruction,
1368b8021494Sopenharmony_ci                              Condition cond,
1369b8021494Sopenharmony_ci                              DataType dt,
1370b8021494Sopenharmony_ci                              DRegister rd,
1371b8021494Sopenharmony_ci                              const DOperand& operand) {
1372b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1373b8021494Sopenharmony_ci  if (type == kVmov) {
1374b8021494Sopenharmony_ci    if (operand.IsImmediate()) {
1375b8021494Sopenharmony_ci      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1376b8021494Sopenharmony_ci      switch (dt.GetValue()) {
1377b8021494Sopenharmony_ci        case I32:
1378b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint32_t>()) {
1379b8021494Sopenharmony_ci            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1380b8021494Sopenharmony_ci            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1381b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1382b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1383b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1384b8021494Sopenharmony_ci              return;
1385b8021494Sopenharmony_ci            }
1386b8021494Sopenharmony_ci            // vmov.i32 d0, 0xff0000ff will translate into
1387b8021494Sopenharmony_ci            // vmov.i64 d0, 0xff0000ffff0000ff
1388b8021494Sopenharmony_ci            if (IsI64BitPattern(imm)) {
1389b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1390b8021494Sopenharmony_ci              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1391b8021494Sopenharmony_ci              return;
1392b8021494Sopenharmony_ci            }
1393b8021494Sopenharmony_ci            // vmov.i32 d0, 0xffab0000 will translate into
1394b8021494Sopenharmony_ci            // vmvn.i32 d0, 0x0054ffff
1395b8021494Sopenharmony_ci            if (cond.Is(al) && CanBeInverted(imm)) {
1396b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1397b8021494Sopenharmony_ci              vmvn(I32, rd, ~imm);
1398b8021494Sopenharmony_ci              return;
1399b8021494Sopenharmony_ci            }
1400b8021494Sopenharmony_ci          }
1401b8021494Sopenharmony_ci          break;
1402b8021494Sopenharmony_ci        case I16:
1403b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint16_t>()) {
1404b8021494Sopenharmony_ci            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1405b8021494Sopenharmony_ci            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1406b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1407b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1408b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1409b8021494Sopenharmony_ci              return;
1410b8021494Sopenharmony_ci            }
1411b8021494Sopenharmony_ci          }
1412b8021494Sopenharmony_ci          break;
1413b8021494Sopenharmony_ci        case I64:
1414b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint64_t>()) {
1415b8021494Sopenharmony_ci            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1416b8021494Sopenharmony_ci            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1417b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1418b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1419b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1420b8021494Sopenharmony_ci              return;
1421b8021494Sopenharmony_ci            }
1422b8021494Sopenharmony_ci            // mov ip, lo(imm64)
1423b8021494Sopenharmony_ci            // vdup d0, ip
1424b8021494Sopenharmony_ci            // vdup is prefered to 'vmov d0[0]' as d0[1] does not need to be
1425b8021494Sopenharmony_ci            // preserved
1426b8021494Sopenharmony_ci            {
1427b8021494Sopenharmony_ci              UseScratchRegisterScope temps(this);
1428b8021494Sopenharmony_ci              Register scratch = temps.Acquire();
1429b8021494Sopenharmony_ci              {
1430b8021494Sopenharmony_ci                // TODO: The scope length was measured empirically. We should
1431b8021494Sopenharmony_ci                // analyse the
1432b8021494Sopenharmony_ci                // worst-case size and add targetted tests.
1433b8021494Sopenharmony_ci                CodeBufferCheckScope scope(this,
1434b8021494Sopenharmony_ci                                           2 * kMaxInstructionSizeInBytes);
1435b8021494Sopenharmony_ci                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1436b8021494Sopenharmony_ci              }
1437b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1438b8021494Sopenharmony_ci              vdup(cond, Untyped32, rd, scratch);
1439b8021494Sopenharmony_ci            }
1440b8021494Sopenharmony_ci            // mov ip, hi(imm64)
1441b8021494Sopenharmony_ci            // vmov d0[1], ip
1442b8021494Sopenharmony_ci            {
1443b8021494Sopenharmony_ci              UseScratchRegisterScope temps(this);
1444b8021494Sopenharmony_ci              Register scratch = temps.Acquire();
1445b8021494Sopenharmony_ci              {
1446b8021494Sopenharmony_ci                // TODO: The scope length was measured empirically. We should
1447b8021494Sopenharmony_ci                // analyse the
1448b8021494Sopenharmony_ci                // worst-case size and add targetted tests.
1449b8021494Sopenharmony_ci                CodeBufferCheckScope scope(this,
1450b8021494Sopenharmony_ci                                           2 * kMaxInstructionSizeInBytes);
1451b8021494Sopenharmony_ci                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1452b8021494Sopenharmony_ci              }
1453b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1454b8021494Sopenharmony_ci              vmov(cond, Untyped32, DRegisterLane(rd, 1), scratch);
1455b8021494Sopenharmony_ci            }
1456b8021494Sopenharmony_ci            return;
1457b8021494Sopenharmony_ci          }
1458b8021494Sopenharmony_ci          break;
1459b8021494Sopenharmony_ci        default:
1460b8021494Sopenharmony_ci          break;
1461b8021494Sopenharmony_ci      }
1462b8021494Sopenharmony_ci      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1463b8021494Sopenharmony_ci      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1464b8021494Sopenharmony_ci        // mov ip, imm32
1465b8021494Sopenharmony_ci        // vdup.16 d0, ip
1466b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1467b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
1468b8021494Sopenharmony_ci        {
1469b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1470b8021494Sopenharmony_ci          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1471b8021494Sopenharmony_ci        }
1472b8021494Sopenharmony_ci        DataTypeValue vdup_dt = Untyped32;
1473b8021494Sopenharmony_ci        switch (dt.GetValue()) {
1474b8021494Sopenharmony_ci          case I16:
1475b8021494Sopenharmony_ci            vdup_dt = Untyped16;
1476b8021494Sopenharmony_ci            break;
1477b8021494Sopenharmony_ci          case I32:
1478b8021494Sopenharmony_ci            vdup_dt = Untyped32;
1479b8021494Sopenharmony_ci            break;
1480b8021494Sopenharmony_ci          default:
1481b8021494Sopenharmony_ci            VIXL_UNREACHABLE();
1482b8021494Sopenharmony_ci        }
1483b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1484b8021494Sopenharmony_ci        vdup(cond, vdup_dt, rd, scratch);
1485b8021494Sopenharmony_ci        return;
1486b8021494Sopenharmony_ci      }
1487b8021494Sopenharmony_ci      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1488b8021494Sopenharmony_ci        float f = neon_imm.GetImmediate<float>();
1489b8021494Sopenharmony_ci        // Punt to vmov.i32
1490b8021494Sopenharmony_ci        // TODO: The scope length was guessed based on the double case below. We
1491b8021494Sopenharmony_ci        // should analyse the worst-case size and add targetted tests.
1492b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1493b8021494Sopenharmony_ci        vmov(cond, I32, rd, FloatToRawbits(f));
1494b8021494Sopenharmony_ci        return;
1495b8021494Sopenharmony_ci      }
1496b8021494Sopenharmony_ci      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1497b8021494Sopenharmony_ci        // Punt to vmov.i64
1498b8021494Sopenharmony_ci        double d = neon_imm.GetImmediate<double>();
1499b8021494Sopenharmony_ci        // TODO: The scope length was measured empirically. We should analyse
1500b8021494Sopenharmony_ci        // the
1501b8021494Sopenharmony_ci        // worst-case size and add targetted tests.
1502b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1503b8021494Sopenharmony_ci        vmov(cond, I64, rd, DoubleToRawbits(d));
1504b8021494Sopenharmony_ci        return;
1505b8021494Sopenharmony_ci      }
1506b8021494Sopenharmony_ci    }
1507b8021494Sopenharmony_ci  }
1508b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1509b8021494Sopenharmony_ci}
1510b8021494Sopenharmony_ci
1511b8021494Sopenharmony_ci
1512b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1513b8021494Sopenharmony_ci                              InstructionCondDtQQop instruction,
1514b8021494Sopenharmony_ci                              Condition cond,
1515b8021494Sopenharmony_ci                              DataType dt,
1516b8021494Sopenharmony_ci                              QRegister rd,
1517b8021494Sopenharmony_ci                              const QOperand& operand) {
1518b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1519b8021494Sopenharmony_ci  if (type == kVmov) {
1520b8021494Sopenharmony_ci    if (operand.IsImmediate()) {
1521b8021494Sopenharmony_ci      const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1522b8021494Sopenharmony_ci      switch (dt.GetValue()) {
1523b8021494Sopenharmony_ci        case I32:
1524b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint32_t>()) {
1525b8021494Sopenharmony_ci            uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1526b8021494Sopenharmony_ci            // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1527b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1528b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1529b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1530b8021494Sopenharmony_ci              return;
1531b8021494Sopenharmony_ci            }
1532b8021494Sopenharmony_ci            // vmov.i32 d0, 0xff0000ff will translate into
1533b8021494Sopenharmony_ci            // vmov.i64 d0, 0xff0000ffff0000ff
1534b8021494Sopenharmony_ci            if (IsI64BitPattern(imm)) {
1535b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1536b8021494Sopenharmony_ci              vmov(cond, I64, rd, replicate<uint64_t>(imm));
1537b8021494Sopenharmony_ci              return;
1538b8021494Sopenharmony_ci            }
1539b8021494Sopenharmony_ci            // vmov.i32 d0, 0xffab0000 will translate into
1540b8021494Sopenharmony_ci            // vmvn.i32 d0, 0x0054ffff
1541b8021494Sopenharmony_ci            if (CanBeInverted(imm)) {
1542b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1543b8021494Sopenharmony_ci              vmvn(cond, I32, rd, ~imm);
1544b8021494Sopenharmony_ci              return;
1545b8021494Sopenharmony_ci            }
1546b8021494Sopenharmony_ci          }
1547b8021494Sopenharmony_ci          break;
1548b8021494Sopenharmony_ci        case I16:
1549b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint16_t>()) {
1550b8021494Sopenharmony_ci            uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1551b8021494Sopenharmony_ci            // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1552b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1553b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1554b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1555b8021494Sopenharmony_ci              return;
1556b8021494Sopenharmony_ci            }
1557b8021494Sopenharmony_ci          }
1558b8021494Sopenharmony_ci          break;
1559b8021494Sopenharmony_ci        case I64:
1560b8021494Sopenharmony_ci          if (neon_imm.CanConvert<uint64_t>()) {
1561b8021494Sopenharmony_ci            uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1562b8021494Sopenharmony_ci            // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1563b8021494Sopenharmony_ci            if (IsI8BitPattern(imm)) {
1564b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1565b8021494Sopenharmony_ci              vmov(cond, I8, rd, imm & 0xff);
1566b8021494Sopenharmony_ci              return;
1567b8021494Sopenharmony_ci            }
1568b8021494Sopenharmony_ci            // mov ip, lo(imm64)
1569b8021494Sopenharmony_ci            // vdup q0, ip
1570b8021494Sopenharmony_ci            // vdup is prefered to 'vmov d0[0]' as d0[1-3] don't need to be
1571b8021494Sopenharmony_ci            // preserved
1572b8021494Sopenharmony_ci            {
1573b8021494Sopenharmony_ci              UseScratchRegisterScope temps(this);
1574b8021494Sopenharmony_ci              Register scratch = temps.Acquire();
1575b8021494Sopenharmony_ci              {
1576b8021494Sopenharmony_ci                CodeBufferCheckScope scope(this,
1577b8021494Sopenharmony_ci                                           2 * kMaxInstructionSizeInBytes);
1578b8021494Sopenharmony_ci                mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1579b8021494Sopenharmony_ci              }
1580b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1581b8021494Sopenharmony_ci              vdup(cond, Untyped32, rd, scratch);
1582b8021494Sopenharmony_ci            }
1583b8021494Sopenharmony_ci            // mov ip, hi(imm64)
1584b8021494Sopenharmony_ci            // vmov.i32 d0[1], ip
1585b8021494Sopenharmony_ci            // vmov d1, d0
1586b8021494Sopenharmony_ci            {
1587b8021494Sopenharmony_ci              UseScratchRegisterScope temps(this);
1588b8021494Sopenharmony_ci              Register scratch = temps.Acquire();
1589b8021494Sopenharmony_ci              {
1590b8021494Sopenharmony_ci                CodeBufferCheckScope scope(this,
1591b8021494Sopenharmony_ci                                           2 * kMaxInstructionSizeInBytes);
1592b8021494Sopenharmony_ci                mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1593b8021494Sopenharmony_ci              }
1594b8021494Sopenharmony_ci              {
1595b8021494Sopenharmony_ci                CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1596b8021494Sopenharmony_ci                vmov(cond,
1597b8021494Sopenharmony_ci                     Untyped32,
1598b8021494Sopenharmony_ci                     DRegisterLane(rd.GetLowDRegister(), 1),
1599b8021494Sopenharmony_ci                     scratch);
1600b8021494Sopenharmony_ci              }
1601b8021494Sopenharmony_ci              CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1602b8021494Sopenharmony_ci              vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1603b8021494Sopenharmony_ci            }
1604b8021494Sopenharmony_ci            return;
1605b8021494Sopenharmony_ci          }
1606b8021494Sopenharmony_ci          break;
1607b8021494Sopenharmony_ci        default:
1608b8021494Sopenharmony_ci          break;
1609b8021494Sopenharmony_ci      }
1610b8021494Sopenharmony_ci      VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1611b8021494Sopenharmony_ci      if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1612b8021494Sopenharmony_ci        // mov ip, imm32
1613b8021494Sopenharmony_ci        // vdup.16 d0, ip
1614b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1615b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
1616b8021494Sopenharmony_ci        {
1617b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1618b8021494Sopenharmony_ci          mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1619b8021494Sopenharmony_ci        }
1620b8021494Sopenharmony_ci        DataTypeValue vdup_dt = Untyped32;
1621b8021494Sopenharmony_ci        switch (dt.GetValue()) {
1622b8021494Sopenharmony_ci          case I16:
1623b8021494Sopenharmony_ci            vdup_dt = Untyped16;
1624b8021494Sopenharmony_ci            break;
1625b8021494Sopenharmony_ci          case I32:
1626b8021494Sopenharmony_ci            vdup_dt = Untyped32;
1627b8021494Sopenharmony_ci            break;
1628b8021494Sopenharmony_ci          default:
1629b8021494Sopenharmony_ci            VIXL_UNREACHABLE();
1630b8021494Sopenharmony_ci        }
1631b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1632b8021494Sopenharmony_ci        vdup(cond, vdup_dt, rd, scratch);
1633b8021494Sopenharmony_ci        return;
1634b8021494Sopenharmony_ci      }
1635b8021494Sopenharmony_ci      if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1636b8021494Sopenharmony_ci        // Punt to vmov.i64
1637b8021494Sopenharmony_ci        float f = neon_imm.GetImmediate<float>();
1638b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1639b8021494Sopenharmony_ci        vmov(cond, I32, rd, FloatToRawbits(f));
1640b8021494Sopenharmony_ci        return;
1641b8021494Sopenharmony_ci      }
1642b8021494Sopenharmony_ci      if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1643b8021494Sopenharmony_ci        // Use vmov to create the double in the low D register, then duplicate
1644b8021494Sopenharmony_ci        // it into the high D register.
1645b8021494Sopenharmony_ci        double d = neon_imm.GetImmediate<double>();
1646b8021494Sopenharmony_ci        CodeBufferCheckScope scope(this, 7 * kMaxInstructionSizeInBytes);
1647b8021494Sopenharmony_ci        vmov(cond, F64, rd.GetLowDRegister(), d);
1648b8021494Sopenharmony_ci        vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1649b8021494Sopenharmony_ci        return;
1650b8021494Sopenharmony_ci      }
1651b8021494Sopenharmony_ci    }
1652b8021494Sopenharmony_ci  }
1653b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1654b8021494Sopenharmony_ci}
1655b8021494Sopenharmony_ci
1656b8021494Sopenharmony_ci
1657b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1658b8021494Sopenharmony_ci                              InstructionCondRL instruction,
1659b8021494Sopenharmony_ci                              Condition cond,
1660b8021494Sopenharmony_ci                              Register rt,
1661b8021494Sopenharmony_ci                              Location* location) {
1662b8021494Sopenharmony_ci  VIXL_ASSERT((type == kLdrb) || (type == kLdrh) || (type == kLdrsb) ||
1663b8021494Sopenharmony_ci              (type == kLdrsh));
1664b8021494Sopenharmony_ci
1665b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1666b8021494Sopenharmony_ci
1667b8021494Sopenharmony_ci  if (location->IsBound()) {
1668b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
1669b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
1670b8021494Sopenharmony_ci    temps.Include(rt);
1671b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
1672b8021494Sopenharmony_ci    uint32_t mask = GetOffsetMask(type, Offset);
1673b8021494Sopenharmony_ci    switch (type) {
1674b8021494Sopenharmony_ci      case kLdrb:
1675b8021494Sopenharmony_ci        ldrb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1676b8021494Sopenharmony_ci        return;
1677b8021494Sopenharmony_ci      case kLdrh:
1678b8021494Sopenharmony_ci        ldrh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1679b8021494Sopenharmony_ci        return;
1680b8021494Sopenharmony_ci      case kLdrsb:
1681b8021494Sopenharmony_ci        ldrsb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1682b8021494Sopenharmony_ci        return;
1683b8021494Sopenharmony_ci      case kLdrsh:
1684b8021494Sopenharmony_ci        ldrsh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1685b8021494Sopenharmony_ci        return;
1686b8021494Sopenharmony_ci      default:
1687b8021494Sopenharmony_ci        VIXL_UNREACHABLE();
1688b8021494Sopenharmony_ci    }
1689b8021494Sopenharmony_ci    return;
1690b8021494Sopenharmony_ci  }
1691b8021494Sopenharmony_ci
1692b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, rt, location);
1693b8021494Sopenharmony_ci}
1694b8021494Sopenharmony_ci
1695b8021494Sopenharmony_ci
1696b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1697b8021494Sopenharmony_ci                              InstructionCondRRL instruction,
1698b8021494Sopenharmony_ci                              Condition cond,
1699b8021494Sopenharmony_ci                              Register rt,
1700b8021494Sopenharmony_ci                              Register rt2,
1701b8021494Sopenharmony_ci                              Location* location) {
1702b8021494Sopenharmony_ci  VIXL_ASSERT(type == kLdrd);
1703b8021494Sopenharmony_ci
1704b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1705b8021494Sopenharmony_ci
1706b8021494Sopenharmony_ci  if (location->IsBound()) {
1707b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1708b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
1709b8021494Sopenharmony_ci    temps.Include(rt, rt2);
1710b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
1711b8021494Sopenharmony_ci    uint32_t mask = GetOffsetMask(type, Offset);
1712b8021494Sopenharmony_ci    ldrd(rt, rt2, MemOperandComputationHelper(cond, scratch, location, mask));
1713b8021494Sopenharmony_ci    return;
1714b8021494Sopenharmony_ci  }
1715b8021494Sopenharmony_ci
1716b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, rt, rt2, location);
1717b8021494Sopenharmony_ci}
1718b8021494Sopenharmony_ci
1719b8021494Sopenharmony_ci
1720b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1721b8021494Sopenharmony_ci                              InstructionCondSizeRMop instruction,
1722b8021494Sopenharmony_ci                              Condition cond,
1723b8021494Sopenharmony_ci                              EncodingSize size,
1724b8021494Sopenharmony_ci                              Register rd,
1725b8021494Sopenharmony_ci                              const MemOperand& operand) {
1726b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1727b8021494Sopenharmony_ci  VIXL_ASSERT(size.IsBest());
1728b8021494Sopenharmony_ci  VIXL_ASSERT((type == kLdr) || (type == kLdrb) || (type == kLdrh) ||
1729b8021494Sopenharmony_ci              (type == kLdrsb) || (type == kLdrsh) || (type == kStr) ||
1730b8021494Sopenharmony_ci              (type == kStrb) || (type == kStrh));
1731b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
1732b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
1733b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
1734b8021494Sopenharmony_ci    int32_t offset = operand.GetOffsetImmediate();
1735b8021494Sopenharmony_ci    uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
1736b8021494Sopenharmony_ci    // Try to maximize the offset used by the MemOperand (load_store_offset).
1737b8021494Sopenharmony_ci    // Add the part which can't be used by the MemOperand (add_offset).
1738b8021494Sopenharmony_ci    uint32_t load_store_offset = offset & extra_offset_mask;
1739b8021494Sopenharmony_ci    uint32_t add_offset = offset & ~extra_offset_mask;
1740b8021494Sopenharmony_ci    if ((add_offset != 0) &&
1741b8021494Sopenharmony_ci        (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
1742b8021494Sopenharmony_ci      load_store_offset = 0;
1743b8021494Sopenharmony_ci      add_offset = offset;
1744b8021494Sopenharmony_ci    }
1745b8021494Sopenharmony_ci    switch (addrmode) {
1746b8021494Sopenharmony_ci      case PreIndex:
1747b8021494Sopenharmony_ci        // Avoid the unpredictable case 'str r0, [r0, imm]!'
1748b8021494Sopenharmony_ci        if (!rn.Is(rd)) {
1749b8021494Sopenharmony_ci          // Pre-Indexed case:
1750b8021494Sopenharmony_ci          // ldr r0, [r1, 12345]! will translate into
1751b8021494Sopenharmony_ci          //   add r1, r1, 12345
1752b8021494Sopenharmony_ci          //   ldr r0, [r1]
1753b8021494Sopenharmony_ci          {
1754b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1755b8021494Sopenharmony_ci            add(cond, rn, rn, add_offset);
1756b8021494Sopenharmony_ci          }
1757b8021494Sopenharmony_ci          {
1758b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1759b8021494Sopenharmony_ci            (this->*instruction)(cond,
1760b8021494Sopenharmony_ci                                 size,
1761b8021494Sopenharmony_ci                                 rd,
1762b8021494Sopenharmony_ci                                 MemOperand(rn, load_store_offset, PreIndex));
1763b8021494Sopenharmony_ci          }
1764b8021494Sopenharmony_ci          return;
1765b8021494Sopenharmony_ci        }
1766b8021494Sopenharmony_ci        break;
1767b8021494Sopenharmony_ci      case Offset: {
1768b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1769b8021494Sopenharmony_ci        // Allow using the destination as a scratch register if possible.
1770b8021494Sopenharmony_ci        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
1771b8021494Sopenharmony_ci            !rd.Is(rn)) {
1772b8021494Sopenharmony_ci          temps.Include(rd);
1773b8021494Sopenharmony_ci        }
1774b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
1775b8021494Sopenharmony_ci        // Offset case:
1776b8021494Sopenharmony_ci        // ldr r0, [r1, 12345] will translate into
1777b8021494Sopenharmony_ci        //   add r0, r1, 12345
1778b8021494Sopenharmony_ci        //   ldr r0, [r0]
1779b8021494Sopenharmony_ci        {
1780b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1781b8021494Sopenharmony_ci          add(cond, scratch, rn, add_offset);
1782b8021494Sopenharmony_ci        }
1783b8021494Sopenharmony_ci        {
1784b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1785b8021494Sopenharmony_ci          (this->*instruction)(cond,
1786b8021494Sopenharmony_ci                               size,
1787b8021494Sopenharmony_ci                               rd,
1788b8021494Sopenharmony_ci                               MemOperand(scratch, load_store_offset));
1789b8021494Sopenharmony_ci        }
1790b8021494Sopenharmony_ci        return;
1791b8021494Sopenharmony_ci      }
1792b8021494Sopenharmony_ci      case PostIndex:
1793b8021494Sopenharmony_ci        // Avoid the unpredictable case 'ldr r0, [r0], imm'
1794b8021494Sopenharmony_ci        if (!rn.Is(rd)) {
1795b8021494Sopenharmony_ci          // Post-indexed case:
1796b8021494Sopenharmony_ci          // ldr r0. [r1], imm32 will translate into
1797b8021494Sopenharmony_ci          //   ldr r0, [r1]
1798b8021494Sopenharmony_ci          //   movw ip. imm32 & 0xffffffff
1799b8021494Sopenharmony_ci          //   movt ip, imm32 >> 16
1800b8021494Sopenharmony_ci          //   add r1, r1, ip
1801b8021494Sopenharmony_ci          {
1802b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1803b8021494Sopenharmony_ci            (this->*instruction)(cond,
1804b8021494Sopenharmony_ci                                 size,
1805b8021494Sopenharmony_ci                                 rd,
1806b8021494Sopenharmony_ci                                 MemOperand(rn, load_store_offset, PostIndex));
1807b8021494Sopenharmony_ci          }
1808b8021494Sopenharmony_ci          {
1809b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1810b8021494Sopenharmony_ci            add(cond, rn, rn, add_offset);
1811b8021494Sopenharmony_ci          }
1812b8021494Sopenharmony_ci          return;
1813b8021494Sopenharmony_ci        }
1814b8021494Sopenharmony_ci        break;
1815b8021494Sopenharmony_ci    }
1816b8021494Sopenharmony_ci  } else if (operand.IsPlainRegister()) {
1817b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
1818b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
1819b8021494Sopenharmony_ci    const Register& rm = operand.GetOffsetRegister();
1820b8021494Sopenharmony_ci    if (rm.IsPC()) {
1821b8021494Sopenharmony_ci      VIXL_ABORT_WITH_MSG(
1822b8021494Sopenharmony_ci          "The MacroAssembler does not convert loads and stores with a PC "
1823b8021494Sopenharmony_ci          "offset register.\n");
1824b8021494Sopenharmony_ci    }
1825b8021494Sopenharmony_ci    if (rn.IsPC()) {
1826b8021494Sopenharmony_ci      if (addrmode == Offset) {
1827b8021494Sopenharmony_ci        if (IsUsingT32()) {
1828b8021494Sopenharmony_ci          VIXL_ABORT_WITH_MSG(
1829b8021494Sopenharmony_ci              "The MacroAssembler does not convert loads and stores with a PC "
1830b8021494Sopenharmony_ci              "base register for T32.\n");
1831b8021494Sopenharmony_ci        }
1832b8021494Sopenharmony_ci      } else {
1833b8021494Sopenharmony_ci        VIXL_ABORT_WITH_MSG(
1834b8021494Sopenharmony_ci            "The MacroAssembler does not convert loads and stores with a PC "
1835b8021494Sopenharmony_ci            "base register in pre-index or post-index mode.\n");
1836b8021494Sopenharmony_ci      }
1837b8021494Sopenharmony_ci    }
1838b8021494Sopenharmony_ci    switch (addrmode) {
1839b8021494Sopenharmony_ci      case PreIndex:
1840b8021494Sopenharmony_ci        // Avoid the unpredictable case 'str r0, [r0, imm]!'
1841b8021494Sopenharmony_ci        if (!rn.Is(rd)) {
1842b8021494Sopenharmony_ci          // Pre-Indexed case:
1843b8021494Sopenharmony_ci          // ldr r0, [r1, r2]! will translate into
1844b8021494Sopenharmony_ci          //   add r1, r1, r2
1845b8021494Sopenharmony_ci          //   ldr r0, [r1]
1846b8021494Sopenharmony_ci          {
1847b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1848b8021494Sopenharmony_ci            if (operand.GetSign().IsPlus()) {
1849b8021494Sopenharmony_ci              add(cond, rn, rn, rm);
1850b8021494Sopenharmony_ci            } else {
1851b8021494Sopenharmony_ci              sub(cond, rn, rn, rm);
1852b8021494Sopenharmony_ci            }
1853b8021494Sopenharmony_ci          }
1854b8021494Sopenharmony_ci          {
1855b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1856b8021494Sopenharmony_ci            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
1857b8021494Sopenharmony_ci          }
1858b8021494Sopenharmony_ci          return;
1859b8021494Sopenharmony_ci        }
1860b8021494Sopenharmony_ci        break;
1861b8021494Sopenharmony_ci      case Offset: {
1862b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1863b8021494Sopenharmony_ci        // Allow using the destination as a scratch register if this is not a
1864b8021494Sopenharmony_ci        // store.
1865b8021494Sopenharmony_ci        // Avoid using PC as a temporary as this has side-effects.
1866b8021494Sopenharmony_ci        if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
1867b8021494Sopenharmony_ci            !rd.IsPC()) {
1868b8021494Sopenharmony_ci          temps.Include(rd);
1869b8021494Sopenharmony_ci        }
1870b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
1871b8021494Sopenharmony_ci        // Offset case:
1872b8021494Sopenharmony_ci        // ldr r0, [r1, r2] will translate into
1873b8021494Sopenharmony_ci        //   add r0, r1, r2
1874b8021494Sopenharmony_ci        //   ldr r0, [r0]
1875b8021494Sopenharmony_ci        {
1876b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1877b8021494Sopenharmony_ci          if (operand.GetSign().IsPlus()) {
1878b8021494Sopenharmony_ci            add(cond, scratch, rn, rm);
1879b8021494Sopenharmony_ci          } else {
1880b8021494Sopenharmony_ci            sub(cond, scratch, rn, rm);
1881b8021494Sopenharmony_ci          }
1882b8021494Sopenharmony_ci        }
1883b8021494Sopenharmony_ci        {
1884b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1885b8021494Sopenharmony_ci          (this->*instruction)(cond, size, rd, MemOperand(scratch, Offset));
1886b8021494Sopenharmony_ci        }
1887b8021494Sopenharmony_ci        return;
1888b8021494Sopenharmony_ci      }
1889b8021494Sopenharmony_ci      case PostIndex:
1890b8021494Sopenharmony_ci        // Avoid the unpredictable case 'ldr r0, [r0], imm'
1891b8021494Sopenharmony_ci        if (!rn.Is(rd)) {
1892b8021494Sopenharmony_ci          // Post-indexed case:
1893b8021494Sopenharmony_ci          // ldr r0. [r1], r2 will translate into
1894b8021494Sopenharmony_ci          //   ldr r0, [r1]
1895b8021494Sopenharmony_ci          //   add r1, r1, r2
1896b8021494Sopenharmony_ci          {
1897b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1898b8021494Sopenharmony_ci            (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
1899b8021494Sopenharmony_ci          }
1900b8021494Sopenharmony_ci          {
1901b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1902b8021494Sopenharmony_ci            if (operand.GetSign().IsPlus()) {
1903b8021494Sopenharmony_ci              add(cond, rn, rn, rm);
1904b8021494Sopenharmony_ci            } else {
1905b8021494Sopenharmony_ci              sub(cond, rn, rn, rm);
1906b8021494Sopenharmony_ci            }
1907b8021494Sopenharmony_ci          }
1908b8021494Sopenharmony_ci          return;
1909b8021494Sopenharmony_ci        }
1910b8021494Sopenharmony_ci        break;
1911b8021494Sopenharmony_ci    }
1912b8021494Sopenharmony_ci  }
1913b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, size, rd, operand);
1914b8021494Sopenharmony_ci}
1915b8021494Sopenharmony_ci
1916b8021494Sopenharmony_ci
1917b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
1918b8021494Sopenharmony_ci                              InstructionCondRRMop instruction,
1919b8021494Sopenharmony_ci                              Condition cond,
1920b8021494Sopenharmony_ci                              Register rt,
1921b8021494Sopenharmony_ci                              Register rt2,
1922b8021494Sopenharmony_ci                              const MemOperand& operand) {
1923b8021494Sopenharmony_ci  if ((type == kLdaexd) || (type == kLdrexd) || (type == kStlex) ||
1924b8021494Sopenharmony_ci      (type == kStlexb) || (type == kStlexh) || (type == kStrex) ||
1925b8021494Sopenharmony_ci      (type == kStrexb) || (type == kStrexh)) {
1926b8021494Sopenharmony_ci    UnimplementedDelegate(type);
1927b8021494Sopenharmony_ci    return;
1928b8021494Sopenharmony_ci  }
1929b8021494Sopenharmony_ci
1930b8021494Sopenharmony_ci  VIXL_ASSERT((type == kLdrd) || (type == kStrd));
1931b8021494Sopenharmony_ci
1932b8021494Sopenharmony_ci  CONTEXT_SCOPE;
1933b8021494Sopenharmony_ci
1934b8021494Sopenharmony_ci  // TODO: Should we allow these cases?
1935b8021494Sopenharmony_ci  if (IsUsingA32()) {
1936b8021494Sopenharmony_ci    // The first register needs to be even.
1937b8021494Sopenharmony_ci    if ((rt.GetCode() & 1) != 0) {
1938b8021494Sopenharmony_ci      UnimplementedDelegate(type);
1939b8021494Sopenharmony_ci      return;
1940b8021494Sopenharmony_ci    }
1941b8021494Sopenharmony_ci    // Registers need to be adjacent.
1942b8021494Sopenharmony_ci    if (((rt.GetCode() + 1) % kNumberOfRegisters) != rt2.GetCode()) {
1943b8021494Sopenharmony_ci      UnimplementedDelegate(type);
1944b8021494Sopenharmony_ci      return;
1945b8021494Sopenharmony_ci    }
1946b8021494Sopenharmony_ci    // LDRD lr, pc [...] is not allowed.
1947b8021494Sopenharmony_ci    if (rt.Is(lr)) {
1948b8021494Sopenharmony_ci      UnimplementedDelegate(type);
1949b8021494Sopenharmony_ci      return;
1950b8021494Sopenharmony_ci    }
1951b8021494Sopenharmony_ci  }
1952b8021494Sopenharmony_ci
1953b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
1954b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
1955b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
1956b8021494Sopenharmony_ci    int32_t offset = operand.GetOffsetImmediate();
1957b8021494Sopenharmony_ci    uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
1958b8021494Sopenharmony_ci    // Try to maximize the offset used by the MemOperand (load_store_offset).
1959b8021494Sopenharmony_ci    // Add the part which can't be used by the MemOperand (add_offset).
1960b8021494Sopenharmony_ci    uint32_t load_store_offset = offset & extra_offset_mask;
1961b8021494Sopenharmony_ci    uint32_t add_offset = offset & ~extra_offset_mask;
1962b8021494Sopenharmony_ci    if ((add_offset != 0) &&
1963b8021494Sopenharmony_ci        (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
1964b8021494Sopenharmony_ci      load_store_offset = 0;
1965b8021494Sopenharmony_ci      add_offset = offset;
1966b8021494Sopenharmony_ci    }
1967b8021494Sopenharmony_ci    switch (addrmode) {
1968b8021494Sopenharmony_ci      case PreIndex: {
1969b8021494Sopenharmony_ci        // Allow using the destinations as a scratch registers if possible.
1970b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1971b8021494Sopenharmony_ci        if (type == kLdrd) {
1972b8021494Sopenharmony_ci          if (!rt.Is(rn)) temps.Include(rt);
1973b8021494Sopenharmony_ci          if (!rt2.Is(rn)) temps.Include(rt2);
1974b8021494Sopenharmony_ci        }
1975b8021494Sopenharmony_ci
1976b8021494Sopenharmony_ci        // Pre-Indexed case:
1977b8021494Sopenharmony_ci        // ldrd r0, r1, [r2, 12345]! will translate into
1978b8021494Sopenharmony_ci        //   add r2, 12345
1979b8021494Sopenharmony_ci        //   ldrd r0, r1, [r2]
1980b8021494Sopenharmony_ci        {
1981b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1982b8021494Sopenharmony_ci          add(cond, rn, rn, add_offset);
1983b8021494Sopenharmony_ci        }
1984b8021494Sopenharmony_ci        {
1985b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1986b8021494Sopenharmony_ci          (this->*instruction)(cond,
1987b8021494Sopenharmony_ci                               rt,
1988b8021494Sopenharmony_ci                               rt2,
1989b8021494Sopenharmony_ci                               MemOperand(rn, load_store_offset, PreIndex));
1990b8021494Sopenharmony_ci        }
1991b8021494Sopenharmony_ci        return;
1992b8021494Sopenharmony_ci      }
1993b8021494Sopenharmony_ci      case Offset: {
1994b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
1995b8021494Sopenharmony_ci        // Allow using the destinations as a scratch registers if possible.
1996b8021494Sopenharmony_ci        if (type == kLdrd) {
1997b8021494Sopenharmony_ci          if (!rt.Is(rn)) temps.Include(rt);
1998b8021494Sopenharmony_ci          if (!rt2.Is(rn)) temps.Include(rt2);
1999b8021494Sopenharmony_ci        }
2000b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
2001b8021494Sopenharmony_ci        // Offset case:
2002b8021494Sopenharmony_ci        // ldrd r0, r1, [r2, 12345] will translate into
2003b8021494Sopenharmony_ci        //   add r0, r2, 12345
2004b8021494Sopenharmony_ci        //   ldrd r0, r1, [r0]
2005b8021494Sopenharmony_ci        {
2006b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2007b8021494Sopenharmony_ci          add(cond, scratch, rn, add_offset);
2008b8021494Sopenharmony_ci        }
2009b8021494Sopenharmony_ci        {
2010b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2011b8021494Sopenharmony_ci          (this->*instruction)(cond,
2012b8021494Sopenharmony_ci                               rt,
2013b8021494Sopenharmony_ci                               rt2,
2014b8021494Sopenharmony_ci                               MemOperand(scratch, load_store_offset));
2015b8021494Sopenharmony_ci        }
2016b8021494Sopenharmony_ci        return;
2017b8021494Sopenharmony_ci      }
2018b8021494Sopenharmony_ci      case PostIndex:
2019b8021494Sopenharmony_ci        // Avoid the unpredictable case 'ldrd r0, r1, [r0], imm'
2020b8021494Sopenharmony_ci        if (!rn.Is(rt) && !rn.Is(rt2)) {
2021b8021494Sopenharmony_ci          // Post-indexed case:
2022b8021494Sopenharmony_ci          // ldrd r0, r1, [r2], imm32 will translate into
2023b8021494Sopenharmony_ci          //   ldrd r0, r1, [r2]
2024b8021494Sopenharmony_ci          //   movw ip. imm32 & 0xffffffff
2025b8021494Sopenharmony_ci          //   movt ip, imm32 >> 16
2026b8021494Sopenharmony_ci          //   add r2, ip
2027b8021494Sopenharmony_ci          {
2028b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2029b8021494Sopenharmony_ci            (this->*instruction)(cond,
2030b8021494Sopenharmony_ci                                 rt,
2031b8021494Sopenharmony_ci                                 rt2,
2032b8021494Sopenharmony_ci                                 MemOperand(rn, load_store_offset, PostIndex));
2033b8021494Sopenharmony_ci          }
2034b8021494Sopenharmony_ci          {
2035b8021494Sopenharmony_ci            CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2036b8021494Sopenharmony_ci            add(cond, rn, rn, add_offset);
2037b8021494Sopenharmony_ci          }
2038b8021494Sopenharmony_ci          return;
2039b8021494Sopenharmony_ci        }
2040b8021494Sopenharmony_ci        break;
2041b8021494Sopenharmony_ci    }
2042b8021494Sopenharmony_ci  }
2043b8021494Sopenharmony_ci  if (operand.IsPlainRegister()) {
2044b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
2045b8021494Sopenharmony_ci    const Register& rm = operand.GetOffsetRegister();
2046b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
2047b8021494Sopenharmony_ci    switch (addrmode) {
2048b8021494Sopenharmony_ci      case PreIndex:
2049b8021494Sopenharmony_ci        // ldrd r0, r1, [r2, r3]! will translate into
2050b8021494Sopenharmony_ci        //   add r2, r3
2051b8021494Sopenharmony_ci        //   ldrd r0, r1, [r2]
2052b8021494Sopenharmony_ci        {
2053b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2054b8021494Sopenharmony_ci          if (operand.GetSign().IsPlus()) {
2055b8021494Sopenharmony_ci            add(cond, rn, rn, rm);
2056b8021494Sopenharmony_ci          } else {
2057b8021494Sopenharmony_ci            sub(cond, rn, rn, rm);
2058b8021494Sopenharmony_ci          }
2059b8021494Sopenharmony_ci        }
2060b8021494Sopenharmony_ci        {
2061b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2062b8021494Sopenharmony_ci          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2063b8021494Sopenharmony_ci        }
2064b8021494Sopenharmony_ci        return;
2065b8021494Sopenharmony_ci      case PostIndex:
2066b8021494Sopenharmony_ci        // ldrd r0, r1, [r2], r3 will translate into
2067b8021494Sopenharmony_ci        //   ldrd r0, r1, [r2]
2068b8021494Sopenharmony_ci        //   add r2, r3
2069b8021494Sopenharmony_ci        {
2070b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2071b8021494Sopenharmony_ci          (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2072b8021494Sopenharmony_ci        }
2073b8021494Sopenharmony_ci        {
2074b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2075b8021494Sopenharmony_ci          if (operand.GetSign().IsPlus()) {
2076b8021494Sopenharmony_ci            add(cond, rn, rn, rm);
2077b8021494Sopenharmony_ci          } else {
2078b8021494Sopenharmony_ci            sub(cond, rn, rn, rm);
2079b8021494Sopenharmony_ci          }
2080b8021494Sopenharmony_ci        }
2081b8021494Sopenharmony_ci        return;
2082b8021494Sopenharmony_ci      case Offset: {
2083b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
2084b8021494Sopenharmony_ci        // Allow using the destinations as a scratch registers if possible.
2085b8021494Sopenharmony_ci        if (type == kLdrd) {
2086b8021494Sopenharmony_ci          if (!rt.Is(rn)) temps.Include(rt);
2087b8021494Sopenharmony_ci          if (!rt2.Is(rn)) temps.Include(rt2);
2088b8021494Sopenharmony_ci        }
2089b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
2090b8021494Sopenharmony_ci        // Offset case:
2091b8021494Sopenharmony_ci        // ldrd r0, r1, [r2, r3] will translate into
2092b8021494Sopenharmony_ci        //   add r0, r2, r3
2093b8021494Sopenharmony_ci        //   ldrd r0, r1, [r0]
2094b8021494Sopenharmony_ci        {
2095b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2096b8021494Sopenharmony_ci          if (operand.GetSign().IsPlus()) {
2097b8021494Sopenharmony_ci            add(cond, scratch, rn, rm);
2098b8021494Sopenharmony_ci          } else {
2099b8021494Sopenharmony_ci            sub(cond, scratch, rn, rm);
2100b8021494Sopenharmony_ci          }
2101b8021494Sopenharmony_ci        }
2102b8021494Sopenharmony_ci        {
2103b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2104b8021494Sopenharmony_ci          (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
2105b8021494Sopenharmony_ci        }
2106b8021494Sopenharmony_ci        return;
2107b8021494Sopenharmony_ci      }
2108b8021494Sopenharmony_ci    }
2109b8021494Sopenharmony_ci  }
2110b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, rt, rt2, operand);
2111b8021494Sopenharmony_ci}
2112b8021494Sopenharmony_ci
2113b8021494Sopenharmony_ci
2114b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
2115b8021494Sopenharmony_ci                              InstructionCondDtSMop instruction,
2116b8021494Sopenharmony_ci                              Condition cond,
2117b8021494Sopenharmony_ci                              DataType dt,
2118b8021494Sopenharmony_ci                              SRegister rd,
2119b8021494Sopenharmony_ci                              const MemOperand& operand) {
2120b8021494Sopenharmony_ci  CONTEXT_SCOPE;
2121b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
2122b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
2123b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
2124b8021494Sopenharmony_ci    int32_t offset = operand.GetOffsetImmediate();
2125b8021494Sopenharmony_ci    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2126b8021494Sopenharmony_ci                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2127b8021494Sopenharmony_ci    if (rn.IsPC()) {
2128b8021494Sopenharmony_ci      VIXL_ABORT_WITH_MSG(
2129b8021494Sopenharmony_ci          "The MacroAssembler does not convert vldr or vstr with a PC base "
2130b8021494Sopenharmony_ci          "register.\n");
2131b8021494Sopenharmony_ci    }
2132b8021494Sopenharmony_ci    switch (addrmode) {
2133b8021494Sopenharmony_ci      case PreIndex:
2134b8021494Sopenharmony_ci        // Pre-Indexed case:
2135b8021494Sopenharmony_ci        // vldr.32 s0, [r1, 12345]! will translate into
2136b8021494Sopenharmony_ci        //   add r1, 12345
2137b8021494Sopenharmony_ci        //   vldr.32 s0, [r1]
2138b8021494Sopenharmony_ci        if (offset != 0) {
2139b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2140b8021494Sopenharmony_ci          add(cond, rn, rn, offset);
2141b8021494Sopenharmony_ci        }
2142b8021494Sopenharmony_ci        {
2143b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2144b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2145b8021494Sopenharmony_ci        }
2146b8021494Sopenharmony_ci        return;
2147b8021494Sopenharmony_ci      case Offset: {
2148b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
2149b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
2150b8021494Sopenharmony_ci        // Offset case:
2151b8021494Sopenharmony_ci        // vldr.32 s0, [r1, 12345] will translate into
2152b8021494Sopenharmony_ci        //   add ip, r1, 12345
2153b8021494Sopenharmony_ci        //   vldr.32 s0, [ip]
2154b8021494Sopenharmony_ci        {
2155b8021494Sopenharmony_ci          VIXL_ASSERT(offset != 0);
2156b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2157b8021494Sopenharmony_ci          add(cond, scratch, rn, offset);
2158b8021494Sopenharmony_ci        }
2159b8021494Sopenharmony_ci        {
2160b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2161b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2162b8021494Sopenharmony_ci        }
2163b8021494Sopenharmony_ci        return;
2164b8021494Sopenharmony_ci      }
2165b8021494Sopenharmony_ci      case PostIndex:
2166b8021494Sopenharmony_ci        // Post-indexed case:
2167b8021494Sopenharmony_ci        // vldr.32 s0, [r1], imm32 will translate into
2168b8021494Sopenharmony_ci        //   vldr.32 s0, [r1]
2169b8021494Sopenharmony_ci        //   movw ip. imm32 & 0xffffffff
2170b8021494Sopenharmony_ci        //   movt ip, imm32 >> 16
2171b8021494Sopenharmony_ci        //   add r1, ip
2172b8021494Sopenharmony_ci        {
2173b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2174b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2175b8021494Sopenharmony_ci        }
2176b8021494Sopenharmony_ci        if (offset != 0) {
2177b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2178b8021494Sopenharmony_ci          add(cond, rn, rn, offset);
2179b8021494Sopenharmony_ci        }
2180b8021494Sopenharmony_ci        return;
2181b8021494Sopenharmony_ci    }
2182b8021494Sopenharmony_ci  }
2183b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2184b8021494Sopenharmony_ci}
2185b8021494Sopenharmony_ci
2186b8021494Sopenharmony_ci
2187b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
2188b8021494Sopenharmony_ci                              InstructionCondDtDMop instruction,
2189b8021494Sopenharmony_ci                              Condition cond,
2190b8021494Sopenharmony_ci                              DataType dt,
2191b8021494Sopenharmony_ci                              DRegister rd,
2192b8021494Sopenharmony_ci                              const MemOperand& operand) {
2193b8021494Sopenharmony_ci  CONTEXT_SCOPE;
2194b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
2195b8021494Sopenharmony_ci    const Register& rn = operand.GetBaseRegister();
2196b8021494Sopenharmony_ci    AddrMode addrmode = operand.GetAddrMode();
2197b8021494Sopenharmony_ci    int32_t offset = operand.GetOffsetImmediate();
2198b8021494Sopenharmony_ci    VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2199b8021494Sopenharmony_ci                ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2200b8021494Sopenharmony_ci    if (rn.IsPC()) {
2201b8021494Sopenharmony_ci      VIXL_ABORT_WITH_MSG(
2202b8021494Sopenharmony_ci          "The MacroAssembler does not convert vldr or vstr with a PC base "
2203b8021494Sopenharmony_ci          "register.\n");
2204b8021494Sopenharmony_ci    }
2205b8021494Sopenharmony_ci    switch (addrmode) {
2206b8021494Sopenharmony_ci      case PreIndex:
2207b8021494Sopenharmony_ci        // Pre-Indexed case:
2208b8021494Sopenharmony_ci        // vldr.64 d0, [r1, 12345]! will translate into
2209b8021494Sopenharmony_ci        //   add r1, 12345
2210b8021494Sopenharmony_ci        //   vldr.64 d0, [r1]
2211b8021494Sopenharmony_ci        if (offset != 0) {
2212b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2213b8021494Sopenharmony_ci          add(cond, rn, rn, offset);
2214b8021494Sopenharmony_ci        }
2215b8021494Sopenharmony_ci        {
2216b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2217b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2218b8021494Sopenharmony_ci        }
2219b8021494Sopenharmony_ci        return;
2220b8021494Sopenharmony_ci      case Offset: {
2221b8021494Sopenharmony_ci        UseScratchRegisterScope temps(this);
2222b8021494Sopenharmony_ci        Register scratch = temps.Acquire();
2223b8021494Sopenharmony_ci        // Offset case:
2224b8021494Sopenharmony_ci        // vldr.64 d0, [r1, 12345] will translate into
2225b8021494Sopenharmony_ci        //   add ip, r1, 12345
2226b8021494Sopenharmony_ci        //   vldr.32 s0, [ip]
2227b8021494Sopenharmony_ci        {
2228b8021494Sopenharmony_ci          VIXL_ASSERT(offset != 0);
2229b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2230b8021494Sopenharmony_ci          add(cond, scratch, rn, offset);
2231b8021494Sopenharmony_ci        }
2232b8021494Sopenharmony_ci        {
2233b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2234b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2235b8021494Sopenharmony_ci        }
2236b8021494Sopenharmony_ci        return;
2237b8021494Sopenharmony_ci      }
2238b8021494Sopenharmony_ci      case PostIndex:
2239b8021494Sopenharmony_ci        // Post-indexed case:
2240b8021494Sopenharmony_ci        // vldr.64 d0. [r1], imm32 will translate into
2241b8021494Sopenharmony_ci        //   vldr.64 d0, [r1]
2242b8021494Sopenharmony_ci        //   movw ip. imm32 & 0xffffffff
2243b8021494Sopenharmony_ci        //   movt ip, imm32 >> 16
2244b8021494Sopenharmony_ci        //   add r1, ip
2245b8021494Sopenharmony_ci        {
2246b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2247b8021494Sopenharmony_ci          (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2248b8021494Sopenharmony_ci        }
2249b8021494Sopenharmony_ci        if (offset != 0) {
2250b8021494Sopenharmony_ci          CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2251b8021494Sopenharmony_ci          add(cond, rn, rn, offset);
2252b8021494Sopenharmony_ci        }
2253b8021494Sopenharmony_ci        return;
2254b8021494Sopenharmony_ci    }
2255b8021494Sopenharmony_ci  }
2256b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2257b8021494Sopenharmony_ci}
2258b8021494Sopenharmony_ci
2259b8021494Sopenharmony_ci
2260b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
2261b8021494Sopenharmony_ci                              InstructionCondMsrOp instruction,
2262b8021494Sopenharmony_ci                              Condition cond,
2263b8021494Sopenharmony_ci                              MaskedSpecialRegister spec_reg,
2264b8021494Sopenharmony_ci                              const Operand& operand) {
2265b8021494Sopenharmony_ci  USE(type);
2266b8021494Sopenharmony_ci  VIXL_ASSERT(type == kMsr);
2267b8021494Sopenharmony_ci  if (operand.IsImmediate()) {
2268b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
2269b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
2270b8021494Sopenharmony_ci    {
2271b8021494Sopenharmony_ci      CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
2272b8021494Sopenharmony_ci      mov(cond, scratch, operand);
2273b8021494Sopenharmony_ci    }
2274b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2275b8021494Sopenharmony_ci    msr(cond, spec_reg, scratch);
2276b8021494Sopenharmony_ci    return;
2277b8021494Sopenharmony_ci  }
2278b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, spec_reg, operand);
2279b8021494Sopenharmony_ci}
2280b8021494Sopenharmony_ci
2281b8021494Sopenharmony_ci
2282b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
2283b8021494Sopenharmony_ci                              InstructionCondDtDL instruction,
2284b8021494Sopenharmony_ci                              Condition cond,
2285b8021494Sopenharmony_ci                              DataType dt,
2286b8021494Sopenharmony_ci                              DRegister rd,
2287b8021494Sopenharmony_ci                              Location* location) {
2288b8021494Sopenharmony_ci  VIXL_ASSERT(type == kVldr);
2289b8021494Sopenharmony_ci
2290b8021494Sopenharmony_ci  CONTEXT_SCOPE;
2291b8021494Sopenharmony_ci
2292b8021494Sopenharmony_ci  if (location->IsBound()) {
2293b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2294b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
2295b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
2296b8021494Sopenharmony_ci    uint32_t mask = GetOffsetMask(type, Offset);
2297b8021494Sopenharmony_ci    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
2298b8021494Sopenharmony_ci    return;
2299b8021494Sopenharmony_ci  }
2300b8021494Sopenharmony_ci
2301b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, location);
2302b8021494Sopenharmony_ci}
2303b8021494Sopenharmony_ci
2304b8021494Sopenharmony_ci
2305b8021494Sopenharmony_civoid MacroAssembler::Delegate(InstructionType type,
2306b8021494Sopenharmony_ci                              InstructionCondDtSL instruction,
2307b8021494Sopenharmony_ci                              Condition cond,
2308b8021494Sopenharmony_ci                              DataType dt,
2309b8021494Sopenharmony_ci                              SRegister rd,
2310b8021494Sopenharmony_ci                              Location* location) {
2311b8021494Sopenharmony_ci  VIXL_ASSERT(type == kVldr);
2312b8021494Sopenharmony_ci
2313b8021494Sopenharmony_ci  CONTEXT_SCOPE;
2314b8021494Sopenharmony_ci
2315b8021494Sopenharmony_ci  if (location->IsBound()) {
2316b8021494Sopenharmony_ci    CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2317b8021494Sopenharmony_ci    UseScratchRegisterScope temps(this);
2318b8021494Sopenharmony_ci    Register scratch = temps.Acquire();
2319b8021494Sopenharmony_ci    uint32_t mask = GetOffsetMask(type, Offset);
2320b8021494Sopenharmony_ci    vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
2321b8021494Sopenharmony_ci    return;
2322b8021494Sopenharmony_ci  }
2323b8021494Sopenharmony_ci
2324b8021494Sopenharmony_ci  Assembler::Delegate(type, instruction, cond, dt, rd, location);
2325b8021494Sopenharmony_ci}
2326b8021494Sopenharmony_ci
2327b8021494Sopenharmony_ci
2328b8021494Sopenharmony_ci#undef CONTEXT_SCOPE
2329b8021494Sopenharmony_ci#undef TOSTRING
2330b8021494Sopenharmony_ci#undef STRINGIFY
2331b8021494Sopenharmony_ci
2332b8021494Sopenharmony_ci// Start of generated code.
2333b8021494Sopenharmony_ci// End of generated code.
2334b8021494Sopenharmony_ci}  // namespace aarch32
2335b8021494Sopenharmony_ci}  // namespace vixl
2336