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