Path: blob/master/dep/vixl/src/aarch64/assembler-aarch64.cc
4261 views
// Copyright 2015, VIXL authors1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are met:5//6// * Redistributions of source code must retain the above copyright notice,7// this list of conditions and the following disclaimer.8// * Redistributions in binary form must reproduce the above copyright notice,9// this list of conditions and the following disclaimer in the documentation10// and/or other materials provided with the distribution.11// * Neither the name of ARM Limited nor the names of its contributors may be12// used to endorse or promote products derived from this software without13// specific prior written permission.14//15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE19// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER22// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,23// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE24// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.252627#include "assembler-aarch64.h"2829#include <cmath>3031#include "macro-assembler-aarch64.h"3233namespace vixl {34namespace aarch64 {3536RawLiteral::RawLiteral(size_t size,37LiteralPool* literal_pool,38DeletionPolicy deletion_policy)39: size_(size),40offset_(0),41low64_(0),42high64_(0),43literal_pool_(literal_pool),44deletion_policy_(deletion_policy) {45VIXL_ASSERT((deletion_policy == kManuallyDeleted) || (literal_pool_ != NULL));46if (deletion_policy == kDeletedOnPoolDestruction) {47literal_pool_->DeleteOnDestruction(this);48}49}505152void Assembler::Reset() { GetBuffer()->Reset(); }535455void Assembler::bind(Label* label) {56BindToOffset(label, GetBuffer()->GetCursorOffset());57}585960void Assembler::BindToOffset(Label* label, ptrdiff_t offset) {61VIXL_ASSERT((offset >= 0) && (offset <= GetBuffer()->GetCursorOffset()));62VIXL_ASSERT(offset % kInstructionSize == 0);6364label->Bind(offset);6566for (Label::LabelLinksIterator it(label); !it.Done(); it.Advance()) {67Instruction* link =68GetBuffer()->GetOffsetAddress<Instruction*>(*it.Current());69link->SetImmPCOffsetTarget(GetLabelAddress<Instruction*>(label));70}71label->ClearAllLinks();72}737475// A common implementation for the LinkAndGet<Type>OffsetTo helpers.76//77// The offset is calculated by aligning the PC and label addresses down to a78// multiple of 1 << element_shift, then calculating the (scaled) offset between79// them. This matches the semantics of adrp, for example.80template <int element_shift>81ptrdiff_t Assembler::LinkAndGetOffsetTo(Label* label) {82VIXL_STATIC_ASSERT(element_shift < (sizeof(ptrdiff_t) * 8));8384if (label->IsBound()) {85uintptr_t pc_offset = GetCursorAddress<uintptr_t>() >> element_shift;86uintptr_t label_offset = GetLabelAddress<uintptr_t>(label) >> element_shift;87return label_offset - pc_offset;88} else {89label->AddLink(GetBuffer()->GetCursorOffset());90return 0;91}92}939495ptrdiff_t Assembler::LinkAndGetByteOffsetTo(Label* label) {96return LinkAndGetOffsetTo<0>(label);97}9899100ptrdiff_t Assembler::LinkAndGetInstructionOffsetTo(Label* label) {101return LinkAndGetOffsetTo<kInstructionSizeLog2>(label);102}103104105ptrdiff_t Assembler::LinkAndGetPageOffsetTo(Label* label) {106return LinkAndGetOffsetTo<kPageSizeLog2>(label);107}108109110void Assembler::place(RawLiteral* literal) {111VIXL_ASSERT(!literal->IsPlaced());112113// Patch instructions using this literal.114if (literal->IsUsed()) {115Instruction* target = GetCursorAddress<Instruction*>();116ptrdiff_t offset = literal->GetLastUse();117bool done;118do {119Instruction* ldr = GetBuffer()->GetOffsetAddress<Instruction*>(offset);120VIXL_ASSERT(ldr->IsLoadLiteral());121122ptrdiff_t imm19 = ldr->GetImmLLiteral();123VIXL_ASSERT(imm19 <= 0);124done = (imm19 == 0);125offset += imm19 * kLiteralEntrySize;126127ldr->SetImmLLiteral(target);128} while (!done);129}130131// "bind" the literal.132literal->SetOffset(GetCursorOffset());133// Copy the data into the pool.134switch (literal->GetSize()) {135case kSRegSizeInBytes:136dc32(literal->GetRawValue32());137break;138case kDRegSizeInBytes:139dc64(literal->GetRawValue64());140break;141default:142VIXL_ASSERT(literal->GetSize() == kQRegSizeInBytes);143dc64(literal->GetRawValue128Low64());144dc64(literal->GetRawValue128High64());145}146147literal->literal_pool_ = NULL;148}149150151ptrdiff_t Assembler::LinkAndGetWordOffsetTo(RawLiteral* literal) {152VIXL_ASSERT(IsWordAligned(GetCursorOffset()));153154bool register_first_use =155(literal->GetLiteralPool() != NULL) && !literal->IsUsed();156157if (literal->IsPlaced()) {158// The literal is "behind", the offset will be negative.159VIXL_ASSERT((literal->GetOffset() - GetCursorOffset()) <= 0);160return (literal->GetOffset() - GetCursorOffset()) >> kLiteralEntrySizeLog2;161}162163ptrdiff_t offset = 0;164// Link all uses together.165if (literal->IsUsed()) {166offset =167(literal->GetLastUse() - GetCursorOffset()) >> kLiteralEntrySizeLog2;168}169literal->SetLastUse(GetCursorOffset());170171if (register_first_use) {172literal->GetLiteralPool()->AddEntry(literal);173}174175return offset;176}177178179// Code generation.180void Assembler::br(const Register& xn) {181VIXL_ASSERT(xn.Is64Bits());182Emit(BR | Rn(xn));183}184185186void Assembler::blr(const Register& xn) {187VIXL_ASSERT(xn.Is64Bits());188Emit(BLR | Rn(xn));189}190191192void Assembler::ret(const Register& xn) {193VIXL_ASSERT(xn.Is64Bits());194Emit(RET | Rn(xn));195}196197198void Assembler::braaz(const Register& xn) {199VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));200VIXL_ASSERT(xn.Is64Bits());201Emit(BRAAZ | Rn(xn) | Rd_mask);202}203204void Assembler::brabz(const Register& xn) {205VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));206VIXL_ASSERT(xn.Is64Bits());207Emit(BRABZ | Rn(xn) | Rd_mask);208}209210void Assembler::blraaz(const Register& xn) {211VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));212VIXL_ASSERT(xn.Is64Bits());213Emit(BLRAAZ | Rn(xn) | Rd_mask);214}215216void Assembler::blrabz(const Register& xn) {217VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));218VIXL_ASSERT(xn.Is64Bits());219Emit(BLRABZ | Rn(xn) | Rd_mask);220}221222void Assembler::retaa() {223VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));224Emit(RETAA | Rn_mask | Rd_mask);225}226227void Assembler::retab() {228VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));229Emit(RETAB | Rn_mask | Rd_mask);230}231232// The Arm ARM names the register Xm but encodes it in the Xd bitfield.233void Assembler::braa(const Register& xn, const Register& xm) {234VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));235VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());236Emit(BRAA | Rn(xn) | RdSP(xm));237}238239void Assembler::brab(const Register& xn, const Register& xm) {240VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));241VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());242Emit(BRAB | Rn(xn) | RdSP(xm));243}244245void Assembler::blraa(const Register& xn, const Register& xm) {246VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));247VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());248Emit(BLRAA | Rn(xn) | RdSP(xm));249}250251void Assembler::blrab(const Register& xn, const Register& xm) {252VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));253VIXL_ASSERT(xn.Is64Bits() && xm.Is64Bits());254Emit(BLRAB | Rn(xn) | RdSP(xm));255}256257258void Assembler::b(int64_t imm26) { Emit(B | ImmUncondBranch(imm26)); }259260261void Assembler::b(int64_t imm19, Condition cond) {262Emit(B_cond | ImmCondBranch(imm19) | cond);263}264265266void Assembler::b(Label* label) {267int64_t offset = LinkAndGetInstructionOffsetTo(label);268VIXL_ASSERT(Instruction::IsValidImmPCOffset(UncondBranchType, offset));269b(static_cast<int>(offset));270}271272273void Assembler::b(Label* label, Condition cond) {274int64_t offset = LinkAndGetInstructionOffsetTo(label);275VIXL_ASSERT(Instruction::IsValidImmPCOffset(CondBranchType, offset));276b(static_cast<int>(offset), cond);277}278279280void Assembler::bl(int64_t imm26) { Emit(BL | ImmUncondBranch(imm26)); }281282283void Assembler::bl(Label* label) {284int64_t offset = LinkAndGetInstructionOffsetTo(label);285VIXL_ASSERT(Instruction::IsValidImmPCOffset(UncondBranchType, offset));286bl(static_cast<int>(offset));287}288289290void Assembler::cbz(const Register& rt, int64_t imm19) {291Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));292}293294295void Assembler::cbz(const Register& rt, Label* label) {296int64_t offset = LinkAndGetInstructionOffsetTo(label);297VIXL_ASSERT(Instruction::IsValidImmPCOffset(CompareBranchType, offset));298cbz(rt, static_cast<int>(offset));299}300301302void Assembler::cbnz(const Register& rt, int64_t imm19) {303Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));304}305306307void Assembler::cbnz(const Register& rt, Label* label) {308int64_t offset = LinkAndGetInstructionOffsetTo(label);309VIXL_ASSERT(Instruction::IsValidImmPCOffset(CompareBranchType, offset));310cbnz(rt, static_cast<int>(offset));311}312313314void Assembler::NEONTable(const VRegister& vd,315const VRegister& vn,316const VRegister& vm,317NEONTableOp op) {318VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));319VIXL_ASSERT(vd.Is16B() || vd.Is8B());320VIXL_ASSERT(vn.Is16B());321VIXL_ASSERT(AreSameFormat(vd, vm));322Emit(op | (vd.IsQ() ? NEON_Q : 0) | Rm(vm) | Rn(vn) | Rd(vd));323}324325326void Assembler::tbl(const VRegister& vd,327const VRegister& vn,328const VRegister& vm) {329VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));330NEONTable(vd, vn, vm, NEON_TBL_1v);331}332333334void Assembler::tbl(const VRegister& vd,335const VRegister& vn,336const VRegister& vn2,337const VRegister& vm) {338USE(vn2);339VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));340VIXL_ASSERT(AreSameFormat(vn, vn2));341VIXL_ASSERT(AreConsecutive(vn, vn2));342NEONTable(vd, vn, vm, NEON_TBL_2v);343}344345346void Assembler::tbl(const VRegister& vd,347const VRegister& vn,348const VRegister& vn2,349const VRegister& vn3,350const VRegister& vm) {351USE(vn2, vn3);352VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));353VIXL_ASSERT(AreSameFormat(vn, vn2, vn3));354VIXL_ASSERT(AreConsecutive(vn, vn2, vn3));355NEONTable(vd, vn, vm, NEON_TBL_3v);356}357358359void Assembler::tbl(const VRegister& vd,360const VRegister& vn,361const VRegister& vn2,362const VRegister& vn3,363const VRegister& vn4,364const VRegister& vm) {365USE(vn2, vn3, vn4);366VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));367VIXL_ASSERT(AreSameFormat(vn, vn2, vn3, vn4));368VIXL_ASSERT(AreConsecutive(vn, vn2, vn3, vn4));369NEONTable(vd, vn, vm, NEON_TBL_4v);370}371372373void Assembler::tbx(const VRegister& vd,374const VRegister& vn,375const VRegister& vm) {376VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));377NEONTable(vd, vn, vm, NEON_TBX_1v);378}379380381void Assembler::tbx(const VRegister& vd,382const VRegister& vn,383const VRegister& vn2,384const VRegister& vm) {385USE(vn2);386VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));387VIXL_ASSERT(AreSameFormat(vn, vn2));388VIXL_ASSERT(AreConsecutive(vn, vn2));389NEONTable(vd, vn, vm, NEON_TBX_2v);390}391392393void Assembler::tbx(const VRegister& vd,394const VRegister& vn,395const VRegister& vn2,396const VRegister& vn3,397const VRegister& vm) {398USE(vn2, vn3);399VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));400VIXL_ASSERT(AreSameFormat(vn, vn2, vn3));401VIXL_ASSERT(AreConsecutive(vn, vn2, vn3));402NEONTable(vd, vn, vm, NEON_TBX_3v);403}404405406void Assembler::tbx(const VRegister& vd,407const VRegister& vn,408const VRegister& vn2,409const VRegister& vn3,410const VRegister& vn4,411const VRegister& vm) {412USE(vn2, vn3, vn4);413VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));414VIXL_ASSERT(AreSameFormat(vn, vn2, vn3, vn4));415VIXL_ASSERT(AreConsecutive(vn, vn2, vn3, vn4));416NEONTable(vd, vn, vm, NEON_TBX_4v);417}418419420void Assembler::tbz(const Register& rt, unsigned bit_pos, int64_t imm14) {421VIXL_ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));422Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));423}424425426void Assembler::tbz(const Register& rt, unsigned bit_pos, Label* label) {427ptrdiff_t offset = LinkAndGetInstructionOffsetTo(label);428VIXL_ASSERT(Instruction::IsValidImmPCOffset(TestBranchType, offset));429tbz(rt, bit_pos, static_cast<int>(offset));430}431432433void Assembler::tbnz(const Register& rt, unsigned bit_pos, int64_t imm14) {434VIXL_ASSERT(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSize)));435Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));436}437438439void Assembler::tbnz(const Register& rt, unsigned bit_pos, Label* label) {440ptrdiff_t offset = LinkAndGetInstructionOffsetTo(label);441VIXL_ASSERT(Instruction::IsValidImmPCOffset(TestBranchType, offset));442tbnz(rt, bit_pos, static_cast<int>(offset));443}444445446void Assembler::adr(const Register& xd, int64_t imm21) {447VIXL_ASSERT(xd.Is64Bits());448Emit(ADR | ImmPCRelAddress(imm21) | Rd(xd));449}450451452void Assembler::adr(const Register& xd, Label* label) {453adr(xd, static_cast<int>(LinkAndGetByteOffsetTo(label)));454}455456457void Assembler::adrp(const Register& xd, int64_t imm21) {458VIXL_ASSERT(xd.Is64Bits());459Emit(ADRP | ImmPCRelAddress(imm21) | Rd(xd));460}461462463void Assembler::adrp(const Register& xd, Label* label) {464VIXL_ASSERT(AllowPageOffsetDependentCode());465adrp(xd, static_cast<int>(LinkAndGetPageOffsetTo(label)));466}467468469void Assembler::add(const Register& rd,470const Register& rn,471const Operand& operand) {472AddSub(rd, rn, operand, LeaveFlags, ADD);473}474475476void Assembler::adds(const Register& rd,477const Register& rn,478const Operand& operand) {479AddSub(rd, rn, operand, SetFlags, ADD);480}481482483void Assembler::cmn(const Register& rn, const Operand& operand) {484Register zr = AppropriateZeroRegFor(rn);485adds(zr, rn, operand);486}487488489void Assembler::sub(const Register& rd,490const Register& rn,491const Operand& operand) {492AddSub(rd, rn, operand, LeaveFlags, SUB);493}494495496void Assembler::subs(const Register& rd,497const Register& rn,498const Operand& operand) {499AddSub(rd, rn, operand, SetFlags, SUB);500}501502503void Assembler::cmp(const Register& rn, const Operand& operand) {504Register zr = AppropriateZeroRegFor(rn);505subs(zr, rn, operand);506}507508509void Assembler::neg(const Register& rd, const Operand& operand) {510Register zr = AppropriateZeroRegFor(rd);511sub(rd, zr, operand);512}513514515void Assembler::negs(const Register& rd, const Operand& operand) {516Register zr = AppropriateZeroRegFor(rd);517subs(rd, zr, operand);518}519520521void Assembler::adc(const Register& rd,522const Register& rn,523const Operand& operand) {524AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);525}526527528void Assembler::adcs(const Register& rd,529const Register& rn,530const Operand& operand) {531AddSubWithCarry(rd, rn, operand, SetFlags, ADC);532}533534535void Assembler::sbc(const Register& rd,536const Register& rn,537const Operand& operand) {538AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);539}540541542void Assembler::sbcs(const Register& rd,543const Register& rn,544const Operand& operand) {545AddSubWithCarry(rd, rn, operand, SetFlags, SBC);546}547548549void Assembler::rmif(const Register& xn, unsigned rotation, StatusFlags flags) {550VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));551VIXL_ASSERT(xn.Is64Bits());552Emit(RMIF | Rn(xn) | ImmRMIFRotation(rotation) | Nzcv(flags));553}554555556void Assembler::setf8(const Register& rn) {557VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));558Emit(SETF8 | Rn(rn));559}560561562void Assembler::setf16(const Register& rn) {563VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));564Emit(SETF16 | Rn(rn));565}566567568void Assembler::ngc(const Register& rd, const Operand& operand) {569Register zr = AppropriateZeroRegFor(rd);570sbc(rd, zr, operand);571}572573574void Assembler::ngcs(const Register& rd, const Operand& operand) {575Register zr = AppropriateZeroRegFor(rd);576sbcs(rd, zr, operand);577}578579580// Logical instructions.581void Assembler::and_(const Register& rd,582const Register& rn,583const Operand& operand) {584Logical(rd, rn, operand, AND);585}586587588void Assembler::ands(const Register& rd,589const Register& rn,590const Operand& operand) {591Logical(rd, rn, operand, ANDS);592}593594595void Assembler::tst(const Register& rn, const Operand& operand) {596ands(AppropriateZeroRegFor(rn), rn, operand);597}598599600void Assembler::bic(const Register& rd,601const Register& rn,602const Operand& operand) {603Logical(rd, rn, operand, BIC);604}605606607void Assembler::bics(const Register& rd,608const Register& rn,609const Operand& operand) {610Logical(rd, rn, operand, BICS);611}612613614void Assembler::orr(const Register& rd,615const Register& rn,616const Operand& operand) {617Logical(rd, rn, operand, ORR);618}619620621void Assembler::orn(const Register& rd,622const Register& rn,623const Operand& operand) {624Logical(rd, rn, operand, ORN);625}626627628void Assembler::eor(const Register& rd,629const Register& rn,630const Operand& operand) {631Logical(rd, rn, operand, EOR);632}633634635void Assembler::eon(const Register& rd,636const Register& rn,637const Operand& operand) {638Logical(rd, rn, operand, EON);639}640641642void Assembler::lslv(const Register& rd,643const Register& rn,644const Register& rm) {645VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());646VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());647Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));648}649650651void Assembler::lsrv(const Register& rd,652const Register& rn,653const Register& rm) {654VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());655VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());656Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));657}658659660void Assembler::asrv(const Register& rd,661const Register& rn,662const Register& rm) {663VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());664VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());665Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));666}667668669void Assembler::rorv(const Register& rd,670const Register& rn,671const Register& rm) {672VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());673VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());674Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));675}676677678// Bitfield operations.679void Assembler::bfm(const Register& rd,680const Register& rn,681unsigned immr,682unsigned imms) {683VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());684Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);685Emit(SF(rd) | BFM | N | ImmR(immr, rd.GetSizeInBits()) |686ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));687}688689690void Assembler::sbfm(const Register& rd,691const Register& rn,692unsigned immr,693unsigned imms) {694VIXL_ASSERT(rd.Is64Bits() || rn.Is32Bits());695Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);696Emit(SF(rd) | SBFM | N | ImmR(immr, rd.GetSizeInBits()) |697ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));698}699700701void Assembler::ubfm(const Register& rd,702const Register& rn,703unsigned immr,704unsigned imms) {705VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());706Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);707Emit(SF(rd) | UBFM | N | ImmR(immr, rd.GetSizeInBits()) |708ImmS(imms, rn.GetSizeInBits()) | Rn(rn) | Rd(rd));709}710711712void Assembler::extr(const Register& rd,713const Register& rn,714const Register& rm,715unsigned lsb) {716VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());717VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());718Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);719Emit(SF(rd) | EXTR | N | Rm(rm) | ImmS(lsb, rn.GetSizeInBits()) | Rn(rn) |720Rd(rd));721}722723724void Assembler::csel(const Register& rd,725const Register& rn,726const Register& rm,727Condition cond) {728ConditionalSelect(rd, rn, rm, cond, CSEL);729}730731732void Assembler::csinc(const Register& rd,733const Register& rn,734const Register& rm,735Condition cond) {736ConditionalSelect(rd, rn, rm, cond, CSINC);737}738739740void Assembler::csinv(const Register& rd,741const Register& rn,742const Register& rm,743Condition cond) {744ConditionalSelect(rd, rn, rm, cond, CSINV);745}746747748void Assembler::csneg(const Register& rd,749const Register& rn,750const Register& rm,751Condition cond) {752ConditionalSelect(rd, rn, rm, cond, CSNEG);753}754755756void Assembler::cset(const Register& rd, Condition cond) {757VIXL_ASSERT((cond != al) && (cond != nv));758Register zr = AppropriateZeroRegFor(rd);759csinc(rd, zr, zr, InvertCondition(cond));760}761762763void Assembler::csetm(const Register& rd, Condition cond) {764VIXL_ASSERT((cond != al) && (cond != nv));765Register zr = AppropriateZeroRegFor(rd);766csinv(rd, zr, zr, InvertCondition(cond));767}768769770void Assembler::cinc(const Register& rd, const Register& rn, Condition cond) {771VIXL_ASSERT((cond != al) && (cond != nv));772csinc(rd, rn, rn, InvertCondition(cond));773}774775776void Assembler::cinv(const Register& rd, const Register& rn, Condition cond) {777VIXL_ASSERT((cond != al) && (cond != nv));778csinv(rd, rn, rn, InvertCondition(cond));779}780781782void Assembler::cneg(const Register& rd, const Register& rn, Condition cond) {783VIXL_ASSERT((cond != al) && (cond != nv));784csneg(rd, rn, rn, InvertCondition(cond));785}786787788void Assembler::ConditionalSelect(const Register& rd,789const Register& rn,790const Register& rm,791Condition cond,792ConditionalSelectOp op) {793VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());794VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());795Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));796}797798799void Assembler::ccmn(const Register& rn,800const Operand& operand,801StatusFlags nzcv,802Condition cond) {803ConditionalCompare(rn, operand, nzcv, cond, CCMN);804}805806807void Assembler::ccmp(const Register& rn,808const Operand& operand,809StatusFlags nzcv,810Condition cond) {811ConditionalCompare(rn, operand, nzcv, cond, CCMP);812}813814815void Assembler::DataProcessing3Source(const Register& rd,816const Register& rn,817const Register& rm,818const Register& ra,819DataProcessing3SourceOp op) {820Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));821}822823824void Assembler::crc32b(const Register& wd,825const Register& wn,826const Register& wm) {827VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));828VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());829Emit(SF(wm) | Rm(wm) | CRC32B | Rn(wn) | Rd(wd));830}831832833void Assembler::crc32h(const Register& wd,834const Register& wn,835const Register& wm) {836VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));837VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());838Emit(SF(wm) | Rm(wm) | CRC32H | Rn(wn) | Rd(wd));839}840841842void Assembler::crc32w(const Register& wd,843const Register& wn,844const Register& wm) {845VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));846VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());847Emit(SF(wm) | Rm(wm) | CRC32W | Rn(wn) | Rd(wd));848}849850851void Assembler::crc32x(const Register& wd,852const Register& wn,853const Register& xm) {854VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));855VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && xm.Is64Bits());856Emit(SF(xm) | Rm(xm) | CRC32X | Rn(wn) | Rd(wd));857}858859860void Assembler::crc32cb(const Register& wd,861const Register& wn,862const Register& wm) {863VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));864VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());865Emit(SF(wm) | Rm(wm) | CRC32CB | Rn(wn) | Rd(wd));866}867868869void Assembler::crc32ch(const Register& wd,870const Register& wn,871const Register& wm) {872VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));873VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());874Emit(SF(wm) | Rm(wm) | CRC32CH | Rn(wn) | Rd(wd));875}876877878void Assembler::crc32cw(const Register& wd,879const Register& wn,880const Register& wm) {881VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));882VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && wm.Is32Bits());883Emit(SF(wm) | Rm(wm) | CRC32CW | Rn(wn) | Rd(wd));884}885886887void Assembler::crc32cx(const Register& wd,888const Register& wn,889const Register& xm) {890VIXL_ASSERT(CPUHas(CPUFeatures::kCRC32));891VIXL_ASSERT(wd.Is32Bits() && wn.Is32Bits() && xm.Is64Bits());892Emit(SF(xm) | Rm(xm) | CRC32CX | Rn(wn) | Rd(wd));893}894895896void Assembler::mul(const Register& rd,897const Register& rn,898const Register& rm) {899VIXL_ASSERT(AreSameSizeAndType(rd, rn, rm));900DataProcessing3Source(rd, rn, rm, AppropriateZeroRegFor(rd), MADD);901}902903904void Assembler::madd(const Register& rd,905const Register& rn,906const Register& rm,907const Register& ra) {908DataProcessing3Source(rd, rn, rm, ra, MADD);909}910911912void Assembler::mneg(const Register& rd,913const Register& rn,914const Register& rm) {915VIXL_ASSERT(AreSameSizeAndType(rd, rn, rm));916DataProcessing3Source(rd, rn, rm, AppropriateZeroRegFor(rd), MSUB);917}918919920void Assembler::msub(const Register& rd,921const Register& rn,922const Register& rm,923const Register& ra) {924DataProcessing3Source(rd, rn, rm, ra, MSUB);925}926927928void Assembler::umaddl(const Register& xd,929const Register& wn,930const Register& wm,931const Register& xa) {932VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());933VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());934DataProcessing3Source(xd, wn, wm, xa, UMADDL_x);935}936937938void Assembler::smaddl(const Register& xd,939const Register& wn,940const Register& wm,941const Register& xa) {942VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());943VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());944DataProcessing3Source(xd, wn, wm, xa, SMADDL_x);945}946947948void Assembler::umsubl(const Register& xd,949const Register& wn,950const Register& wm,951const Register& xa) {952VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());953VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());954DataProcessing3Source(xd, wn, wm, xa, UMSUBL_x);955}956957958void Assembler::smsubl(const Register& xd,959const Register& wn,960const Register& wm,961const Register& xa) {962VIXL_ASSERT(xd.Is64Bits() && xa.Is64Bits());963VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());964DataProcessing3Source(xd, wn, wm, xa, SMSUBL_x);965}966967968void Assembler::smull(const Register& xd,969const Register& wn,970const Register& wm) {971VIXL_ASSERT(xd.Is64Bits());972VIXL_ASSERT(wn.Is32Bits() && wm.Is32Bits());973DataProcessing3Source(xd, wn, wm, xzr, SMADDL_x);974}975976977void Assembler::sdiv(const Register& rd,978const Register& rn,979const Register& rm) {980VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());981VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());982Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));983}984985986void Assembler::smulh(const Register& xd,987const Register& xn,988const Register& xm) {989VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());990DataProcessing3Source(xd, xn, xm, xzr, SMULH_x);991}992993994void Assembler::umulh(const Register& xd,995const Register& xn,996const Register& xm) {997VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());998DataProcessing3Source(xd, xn, xm, xzr, UMULH_x);999}100010011002void Assembler::udiv(const Register& rd,1003const Register& rn,1004const Register& rm) {1005VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());1006VIXL_ASSERT(rd.GetSizeInBits() == rm.GetSizeInBits());1007Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));1008}100910101011void Assembler::rbit(const Register& rd, const Register& rn) {1012DataProcessing1Source(rd, rn, RBIT);1013}101410151016void Assembler::rev16(const Register& rd, const Register& rn) {1017DataProcessing1Source(rd, rn, REV16);1018}101910201021void Assembler::rev32(const Register& xd, const Register& xn) {1022VIXL_ASSERT(xd.Is64Bits());1023DataProcessing1Source(xd, xn, REV);1024}102510261027void Assembler::rev(const Register& rd, const Register& rn) {1028DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);1029}103010311032void Assembler::clz(const Register& rd, const Register& rn) {1033DataProcessing1Source(rd, rn, CLZ);1034}103510361037void Assembler::cls(const Register& rd, const Register& rn) {1038DataProcessing1Source(rd, rn, CLS);1039}10401041#define PAUTH_VARIATIONS(V) \1042V(paci, PACI) \1043V(pacd, PACD) \1044V(auti, AUTI) \1045V(autd, AUTD)10461047#define VIXL_DEFINE_ASM_FUNC(PRE, OP) \1048void Assembler::PRE##a(const Register& xd, const Register& xn) { \1049VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth)); \1050VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits()); \1051Emit(SF(xd) | OP##A | Rd(xd) | RnSP(xn)); \1052} \1053\1054void Assembler::PRE##za(const Register& xd) { \1055VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth)); \1056VIXL_ASSERT(xd.Is64Bits()); \1057Emit(SF(xd) | OP##ZA | Rd(xd) | Rn(xzr)); \1058} \1059\1060void Assembler::PRE##b(const Register& xd, const Register& xn) { \1061VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth)); \1062VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits()); \1063Emit(SF(xd) | OP##B | Rd(xd) | RnSP(xn)); \1064} \1065\1066void Assembler::PRE##zb(const Register& xd) { \1067VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth)); \1068VIXL_ASSERT(xd.Is64Bits()); \1069Emit(SF(xd) | OP##ZB | Rd(xd) | Rn(xzr)); \1070}10711072PAUTH_VARIATIONS(VIXL_DEFINE_ASM_FUNC)1073#undef VIXL_DEFINE_ASM_FUNC10741075void Assembler::pacga(const Register& xd,1076const Register& xn,1077const Register& xm) {1078VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric));1079VIXL_ASSERT(xd.Is64Bits() && xn.Is64Bits() && xm.Is64Bits());1080Emit(SF(xd) | PACGA | Rd(xd) | Rn(xn) | RmSP(xm));1081}10821083void Assembler::xpaci(const Register& xd) {1084VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));1085VIXL_ASSERT(xd.Is64Bits());1086Emit(SF(xd) | XPACI | Rd(xd) | Rn(xzr));1087}10881089void Assembler::xpacd(const Register& xd) {1090VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));1091VIXL_ASSERT(xd.Is64Bits());1092Emit(SF(xd) | XPACD | Rd(xd) | Rn(xzr));1093}109410951096void Assembler::ldp(const CPURegister& rt,1097const CPURegister& rt2,1098const MemOperand& src) {1099LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));1100}110111021103void Assembler::stp(const CPURegister& rt,1104const CPURegister& rt2,1105const MemOperand& dst) {1106LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));1107}110811091110void Assembler::ldpsw(const Register& xt,1111const Register& xt2,1112const MemOperand& src) {1113VIXL_ASSERT(xt.Is64Bits() && xt2.Is64Bits());1114LoadStorePair(xt, xt2, src, LDPSW_x);1115}111611171118void Assembler::LoadStorePair(const CPURegister& rt,1119const CPURegister& rt2,1120const MemOperand& addr,1121LoadStorePairOp op) {1122VIXL_ASSERT(CPUHas(rt, rt2));11231124// 'rt' and 'rt2' can only be aliased for stores.1125VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));1126VIXL_ASSERT(AreSameSizeAndType(rt, rt2));1127VIXL_ASSERT(IsImmLSPair(addr.GetOffset(), CalcLSPairDataSize(op)));11281129int offset = static_cast<int>(addr.GetOffset());1130Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.GetBaseRegister()) |1131ImmLSPair(offset, CalcLSPairDataSize(op));11321133Instr addrmodeop;1134if (addr.IsImmediateOffset()) {1135addrmodeop = LoadStorePairOffsetFixed;1136} else {1137if (addr.IsImmediatePreIndex()) {1138addrmodeop = LoadStorePairPreIndexFixed;1139} else {1140VIXL_ASSERT(addr.IsImmediatePostIndex());1141addrmodeop = LoadStorePairPostIndexFixed;1142}1143}11441145Instr emitop = addrmodeop | memop;11461147// Only X registers may be specified for ldpsw.1148VIXL_ASSERT(((emitop & LoadStorePairMask) != LDPSW_x) || rt.IsX());11491150Emit(emitop);1151}115211531154void Assembler::ldnp(const CPURegister& rt,1155const CPURegister& rt2,1156const MemOperand& src) {1157LoadStorePairNonTemporal(rt, rt2, src, LoadPairNonTemporalOpFor(rt, rt2));1158}115911601161void Assembler::stnp(const CPURegister& rt,1162const CPURegister& rt2,1163const MemOperand& dst) {1164LoadStorePairNonTemporal(rt, rt2, dst, StorePairNonTemporalOpFor(rt, rt2));1165}116611671168void Assembler::LoadStorePairNonTemporal(const CPURegister& rt,1169const CPURegister& rt2,1170const MemOperand& addr,1171LoadStorePairNonTemporalOp op) {1172VIXL_ASSERT(CPUHas(rt, rt2));11731174VIXL_ASSERT(!rt.Is(rt2));1175VIXL_ASSERT(AreSameSizeAndType(rt, rt2));1176VIXL_ASSERT(addr.IsImmediateOffset());11771178unsigned size =1179CalcLSPairDataSize(static_cast<LoadStorePairOp>(1180static_cast<uint32_t>(op) & static_cast<uint32_t>(LoadStorePairMask)));1181VIXL_ASSERT(IsImmLSPair(addr.GetOffset(), size));1182int offset = static_cast<int>(addr.GetOffset());1183Emit(op | Rt(rt) | Rt2(rt2) | RnSP(addr.GetBaseRegister()) |1184ImmLSPair(offset, size));1185}118611871188// Memory instructions.1189void Assembler::ldrb(const Register& rt,1190const MemOperand& src,1191LoadStoreScalingOption option) {1192VIXL_ASSERT(option != RequireUnscaledOffset);1193VIXL_ASSERT(option != PreferUnscaledOffset);1194LoadStore(rt, src, LDRB_w, option);1195}119611971198void Assembler::strb(const Register& rt,1199const MemOperand& dst,1200LoadStoreScalingOption option) {1201VIXL_ASSERT(option != RequireUnscaledOffset);1202VIXL_ASSERT(option != PreferUnscaledOffset);1203LoadStore(rt, dst, STRB_w, option);1204}120512061207void Assembler::ldrsb(const Register& rt,1208const MemOperand& src,1209LoadStoreScalingOption option) {1210VIXL_ASSERT(option != RequireUnscaledOffset);1211VIXL_ASSERT(option != PreferUnscaledOffset);1212LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w, option);1213}121412151216void Assembler::ldrh(const Register& rt,1217const MemOperand& src,1218LoadStoreScalingOption option) {1219VIXL_ASSERT(option != RequireUnscaledOffset);1220VIXL_ASSERT(option != PreferUnscaledOffset);1221LoadStore(rt, src, LDRH_w, option);1222}122312241225void Assembler::strh(const Register& rt,1226const MemOperand& dst,1227LoadStoreScalingOption option) {1228VIXL_ASSERT(option != RequireUnscaledOffset);1229VIXL_ASSERT(option != PreferUnscaledOffset);1230LoadStore(rt, dst, STRH_w, option);1231}123212331234void Assembler::ldrsh(const Register& rt,1235const MemOperand& src,1236LoadStoreScalingOption option) {1237VIXL_ASSERT(option != RequireUnscaledOffset);1238VIXL_ASSERT(option != PreferUnscaledOffset);1239LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w, option);1240}124112421243void Assembler::ldr(const CPURegister& rt,1244const MemOperand& src,1245LoadStoreScalingOption option) {1246VIXL_ASSERT(option != RequireUnscaledOffset);1247VIXL_ASSERT(option != PreferUnscaledOffset);1248LoadStore(rt, src, LoadOpFor(rt), option);1249}125012511252void Assembler::str(const CPURegister& rt,1253const MemOperand& dst,1254LoadStoreScalingOption option) {1255VIXL_ASSERT(option != RequireUnscaledOffset);1256VIXL_ASSERT(option != PreferUnscaledOffset);1257LoadStore(rt, dst, StoreOpFor(rt), option);1258}125912601261void Assembler::ldrsw(const Register& xt,1262const MemOperand& src,1263LoadStoreScalingOption option) {1264VIXL_ASSERT(xt.Is64Bits());1265VIXL_ASSERT(option != RequireUnscaledOffset);1266VIXL_ASSERT(option != PreferUnscaledOffset);1267LoadStore(xt, src, LDRSW_x, option);1268}126912701271void Assembler::ldurb(const Register& rt,1272const MemOperand& src,1273LoadStoreScalingOption option) {1274VIXL_ASSERT(option != RequireScaledOffset);1275VIXL_ASSERT(option != PreferScaledOffset);1276LoadStore(rt, src, LDRB_w, option);1277}127812791280void Assembler::sturb(const Register& rt,1281const MemOperand& dst,1282LoadStoreScalingOption option) {1283VIXL_ASSERT(option != RequireScaledOffset);1284VIXL_ASSERT(option != PreferScaledOffset);1285LoadStore(rt, dst, STRB_w, option);1286}128712881289void Assembler::ldursb(const Register& rt,1290const MemOperand& src,1291LoadStoreScalingOption option) {1292VIXL_ASSERT(option != RequireScaledOffset);1293VIXL_ASSERT(option != PreferScaledOffset);1294LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w, option);1295}129612971298void Assembler::ldurh(const Register& rt,1299const MemOperand& src,1300LoadStoreScalingOption option) {1301VIXL_ASSERT(option != RequireScaledOffset);1302VIXL_ASSERT(option != PreferScaledOffset);1303LoadStore(rt, src, LDRH_w, option);1304}130513061307void Assembler::sturh(const Register& rt,1308const MemOperand& dst,1309LoadStoreScalingOption option) {1310VIXL_ASSERT(option != RequireScaledOffset);1311VIXL_ASSERT(option != PreferScaledOffset);1312LoadStore(rt, dst, STRH_w, option);1313}131413151316void Assembler::ldursh(const Register& rt,1317const MemOperand& src,1318LoadStoreScalingOption option) {1319VIXL_ASSERT(option != RequireScaledOffset);1320VIXL_ASSERT(option != PreferScaledOffset);1321LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w, option);1322}132313241325void Assembler::ldur(const CPURegister& rt,1326const MemOperand& src,1327LoadStoreScalingOption option) {1328VIXL_ASSERT(option != RequireScaledOffset);1329VIXL_ASSERT(option != PreferScaledOffset);1330LoadStore(rt, src, LoadOpFor(rt), option);1331}133213331334void Assembler::stur(const CPURegister& rt,1335const MemOperand& dst,1336LoadStoreScalingOption option) {1337VIXL_ASSERT(option != RequireScaledOffset);1338VIXL_ASSERT(option != PreferScaledOffset);1339LoadStore(rt, dst, StoreOpFor(rt), option);1340}134113421343void Assembler::ldursw(const Register& xt,1344const MemOperand& src,1345LoadStoreScalingOption option) {1346VIXL_ASSERT(xt.Is64Bits());1347VIXL_ASSERT(option != RequireScaledOffset);1348VIXL_ASSERT(option != PreferScaledOffset);1349LoadStore(xt, src, LDRSW_x, option);1350}135113521353void Assembler::ldraa(const Register& xt, const MemOperand& src) {1354VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));1355LoadStorePAC(xt, src, LDRAA);1356}135713581359void Assembler::ldrab(const Register& xt, const MemOperand& src) {1360VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));1361LoadStorePAC(xt, src, LDRAB);1362}136313641365void Assembler::ldrsw(const Register& xt, RawLiteral* literal) {1366VIXL_ASSERT(xt.Is64Bits());1367VIXL_ASSERT(literal->GetSize() == kWRegSizeInBytes);1368ldrsw(xt, static_cast<int>(LinkAndGetWordOffsetTo(literal)));1369}137013711372void Assembler::ldr(const CPURegister& rt, RawLiteral* literal) {1373VIXL_ASSERT(CPUHas(rt));1374VIXL_ASSERT(literal->GetSize() == static_cast<size_t>(rt.GetSizeInBytes()));1375ldr(rt, static_cast<int>(LinkAndGetWordOffsetTo(literal)));1376}137713781379void Assembler::ldrsw(const Register& rt, int64_t imm19) {1380Emit(LDRSW_x_lit | ImmLLiteral(imm19) | Rt(rt));1381}138213831384void Assembler::ldr(const CPURegister& rt, int64_t imm19) {1385VIXL_ASSERT(CPUHas(rt));1386LoadLiteralOp op = LoadLiteralOpFor(rt);1387Emit(op | ImmLLiteral(imm19) | Rt(rt));1388}138913901391void Assembler::prfm(int op, int64_t imm19) {1392Emit(PRFM_lit | ImmPrefetchOperation(op) | ImmLLiteral(imm19));1393}13941395void Assembler::prfm(PrefetchOperation op, int64_t imm19) {1396// Passing unnamed values in 'op' is undefined behaviour in C++.1397VIXL_ASSERT(IsNamedPrefetchOperation(op));1398prfm(static_cast<int>(op), imm19);1399}140014011402// Exclusive-access instructions.1403void Assembler::stxrb(const Register& rs,1404const Register& rt,1405const MemOperand& dst) {1406VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1407Emit(STXRB_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1408}140914101411void Assembler::stxrh(const Register& rs,1412const Register& rt,1413const MemOperand& dst) {1414VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1415Emit(STXRH_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1416}141714181419void Assembler::stxr(const Register& rs,1420const Register& rt,1421const MemOperand& dst) {1422VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1423LoadStoreExclusive op = rt.Is64Bits() ? STXR_x : STXR_w;1424Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1425}142614271428void Assembler::ldxrb(const Register& rt, const MemOperand& src) {1429VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1430Emit(LDXRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1431}143214331434void Assembler::ldxrh(const Register& rt, const MemOperand& src) {1435VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1436Emit(LDXRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1437}143814391440void Assembler::ldxr(const Register& rt, const MemOperand& src) {1441VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1442LoadStoreExclusive op = rt.Is64Bits() ? LDXR_x : LDXR_w;1443Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1444}144514461447void Assembler::stxp(const Register& rs,1448const Register& rt,1449const Register& rt2,1450const MemOperand& dst) {1451VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());1452VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1453LoadStoreExclusive op = rt.Is64Bits() ? STXP_x : STXP_w;1454Emit(op | Rs(rs) | Rt(rt) | Rt2(rt2) | RnSP(dst.GetBaseRegister()));1455}145614571458void Assembler::ldxp(const Register& rt,1459const Register& rt2,1460const MemOperand& src) {1461VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());1462VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1463LoadStoreExclusive op = rt.Is64Bits() ? LDXP_x : LDXP_w;1464Emit(op | Rs_mask | Rt(rt) | Rt2(rt2) | RnSP(src.GetBaseRegister()));1465}146614671468void Assembler::stlxrb(const Register& rs,1469const Register& rt,1470const MemOperand& dst) {1471VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1472Emit(STLXRB_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1473}147414751476void Assembler::stlxrh(const Register& rs,1477const Register& rt,1478const MemOperand& dst) {1479VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1480Emit(STLXRH_w | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1481}148214831484void Assembler::stlxr(const Register& rs,1485const Register& rt,1486const MemOperand& dst) {1487VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1488LoadStoreExclusive op = rt.Is64Bits() ? STLXR_x : STLXR_w;1489Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1490}149114921493void Assembler::ldaxrb(const Register& rt, const MemOperand& src) {1494VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1495Emit(LDAXRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1496}149714981499void Assembler::ldaxrh(const Register& rt, const MemOperand& src) {1500VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1501Emit(LDAXRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1502}150315041505void Assembler::ldaxr(const Register& rt, const MemOperand& src) {1506VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1507LoadStoreExclusive op = rt.Is64Bits() ? LDAXR_x : LDAXR_w;1508Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1509}151015111512void Assembler::stlxp(const Register& rs,1513const Register& rt,1514const Register& rt2,1515const MemOperand& dst) {1516VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());1517VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1518LoadStoreExclusive op = rt.Is64Bits() ? STLXP_x : STLXP_w;1519Emit(op | Rs(rs) | Rt(rt) | Rt2(rt2) | RnSP(dst.GetBaseRegister()));1520}152115221523void Assembler::ldaxp(const Register& rt,1524const Register& rt2,1525const MemOperand& src) {1526VIXL_ASSERT(rt.GetSizeInBits() == rt2.GetSizeInBits());1527VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1528LoadStoreExclusive op = rt.Is64Bits() ? LDAXP_x : LDAXP_w;1529Emit(op | Rs_mask | Rt(rt) | Rt2(rt2) | RnSP(src.GetBaseRegister()));1530}153115321533void Assembler::stlrb(const Register& rt, const MemOperand& dst) {1534VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1535Emit(STLRB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1536}15371538void Assembler::stlurb(const Register& rt, const MemOperand& dst) {1539VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1540VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));15411542Instr base = RnSP(dst.GetBaseRegister());1543int64_t offset = dst.GetOffset();1544Emit(STLURB | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1545}154615471548void Assembler::stlrh(const Register& rt, const MemOperand& dst) {1549VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1550Emit(STLRH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1551}15521553void Assembler::stlurh(const Register& rt, const MemOperand& dst) {1554VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1555VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));15561557Instr base = RnSP(dst.GetBaseRegister());1558int64_t offset = dst.GetOffset();1559Emit(STLURH | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1560}156115621563void Assembler::stlr(const Register& rt, const MemOperand& dst) {1564VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1565LoadStoreExclusive op = rt.Is64Bits() ? STLR_x : STLR_w;1566Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1567}15681569void Assembler::stlur(const Register& rt, const MemOperand& dst) {1570VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1571VIXL_ASSERT(dst.IsImmediateOffset() && IsImmLSUnscaled(dst.GetOffset()));15721573Instr base = RnSP(dst.GetBaseRegister());1574int64_t offset = dst.GetOffset();1575Instr op = rt.Is64Bits() ? STLUR_x : STLUR_w;1576Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1577}157815791580void Assembler::ldarb(const Register& rt, const MemOperand& src) {1581VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1582Emit(LDARB_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1583}158415851586void Assembler::ldarh(const Register& rt, const MemOperand& src) {1587VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1588Emit(LDARH_w | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1589}159015911592void Assembler::ldar(const Register& rt, const MemOperand& src) {1593VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1594LoadStoreExclusive op = rt.Is64Bits() ? LDAR_x : LDAR_w;1595Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1596}159715981599void Assembler::stllrb(const Register& rt, const MemOperand& dst) {1600VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1601VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1602Emit(STLLRB | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1603}160416051606void Assembler::stllrh(const Register& rt, const MemOperand& dst) {1607VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1608VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1609Emit(STLLRH | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1610}161116121613void Assembler::stllr(const Register& rt, const MemOperand& dst) {1614VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1615VIXL_ASSERT(dst.IsImmediateOffset() && (dst.GetOffset() == 0));1616LoadStoreExclusive op = rt.Is64Bits() ? STLLR_x : STLLR_w;1617Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(dst.GetBaseRegister()));1618}161916201621void Assembler::ldlarb(const Register& rt, const MemOperand& src) {1622VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1623VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1624Emit(LDLARB | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1625}162616271628void Assembler::ldlarh(const Register& rt, const MemOperand& src) {1629VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1630VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1631Emit(LDLARH | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1632}163316341635void Assembler::ldlar(const Register& rt, const MemOperand& src) {1636VIXL_ASSERT(CPUHas(CPUFeatures::kLORegions));1637VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1638LoadStoreExclusive op = rt.Is64Bits() ? LDLAR_x : LDLAR_w;1639Emit(op | Rs_mask | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister()));1640}164116421643// clang-format off1644#define COMPARE_AND_SWAP_W_X_LIST(V) \1645V(cas, CAS) \1646V(casa, CASA) \1647V(casl, CASL) \1648V(casal, CASAL)1649// clang-format on16501651#define VIXL_DEFINE_ASM_FUNC(FN, OP) \1652void Assembler::FN(const Register& rs, \1653const Register& rt, \1654const MemOperand& src) { \1655VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1656VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \1657VIXL_ASSERT(AreSameFormat(rs, rt)); \1658LoadStoreExclusive op = rt.Is64Bits() ? OP##_x : OP##_w; \1659Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \1660}1661COMPARE_AND_SWAP_W_X_LIST(VIXL_DEFINE_ASM_FUNC)1662#undef VIXL_DEFINE_ASM_FUNC16631664// clang-format off1665#define COMPARE_AND_SWAP_W_LIST(V) \1666V(casb, CASB) \1667V(casab, CASAB) \1668V(caslb, CASLB) \1669V(casalb, CASALB) \1670V(cash, CASH) \1671V(casah, CASAH) \1672V(caslh, CASLH) \1673V(casalh, CASALH)1674// clang-format on16751676#define VIXL_DEFINE_ASM_FUNC(FN, OP) \1677void Assembler::FN(const Register& rs, \1678const Register& rt, \1679const MemOperand& src) { \1680VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1681VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \1682Emit(OP | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \1683}1684COMPARE_AND_SWAP_W_LIST(VIXL_DEFINE_ASM_FUNC)1685#undef VIXL_DEFINE_ASM_FUNC168616871688// clang-format off1689#define COMPARE_AND_SWAP_PAIR_LIST(V) \1690V(casp, CASP) \1691V(caspa, CASPA) \1692V(caspl, CASPL) \1693V(caspal, CASPAL)1694// clang-format on16951696#define VIXL_DEFINE_ASM_FUNC(FN, OP) \1697void Assembler::FN(const Register& rs, \1698const Register& rs1, \1699const Register& rt, \1700const Register& rt1, \1701const MemOperand& src) { \1702VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1703USE(rs1, rt1); \1704VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \1705VIXL_ASSERT(AreEven(rs, rt)); \1706VIXL_ASSERT(AreConsecutive(rs, rs1)); \1707VIXL_ASSERT(AreConsecutive(rt, rt1)); \1708VIXL_ASSERT(AreSameFormat(rs, rs1, rt, rt1)); \1709LoadStoreExclusive op = rt.Is64Bits() ? OP##_x : OP##_w; \1710Emit(op | Rs(rs) | Rt(rt) | Rt2_mask | RnSP(src.GetBaseRegister())); \1711}1712COMPARE_AND_SWAP_PAIR_LIST(VIXL_DEFINE_ASM_FUNC)1713#undef VIXL_DEFINE_ASM_FUNC17141715// These macros generate all the variations of the atomic memory operations,1716// e.g. ldadd, ldadda, ldaddb, staddl, etc.1717// For a full list of the methods with comments, see the assembler header file.17181719// clang-format off1720#define ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(V, DEF) \1721V(DEF, add, LDADD) \1722V(DEF, clr, LDCLR) \1723V(DEF, eor, LDEOR) \1724V(DEF, set, LDSET) \1725V(DEF, smax, LDSMAX) \1726V(DEF, smin, LDSMIN) \1727V(DEF, umax, LDUMAX) \1728V(DEF, umin, LDUMIN)17291730#define ATOMIC_MEMORY_STORE_MODES(V, NAME, OP) \1731V(NAME, OP##_x, OP##_w) \1732V(NAME##l, OP##L_x, OP##L_w) \1733V(NAME##b, OP##B, OP##B) \1734V(NAME##lb, OP##LB, OP##LB) \1735V(NAME##h, OP##H, OP##H) \1736V(NAME##lh, OP##LH, OP##LH)17371738#define ATOMIC_MEMORY_LOAD_MODES(V, NAME, OP) \1739ATOMIC_MEMORY_STORE_MODES(V, NAME, OP) \1740V(NAME##a, OP##A_x, OP##A_w) \1741V(NAME##al, OP##AL_x, OP##AL_w) \1742V(NAME##ab, OP##AB, OP##AB) \1743V(NAME##alb, OP##ALB, OP##ALB) \1744V(NAME##ah, OP##AH, OP##AH) \1745V(NAME##alh, OP##ALH, OP##ALH)1746// clang-format on17471748#define DEFINE_ASM_LOAD_FUNC(FN, OP_X, OP_W) \1749void Assembler::ld##FN(const Register& rs, \1750const Register& rt, \1751const MemOperand& src) { \1752VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1753VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \1754AtomicMemoryOp op = rt.Is64Bits() ? OP_X : OP_W; \1755Emit(op | Rs(rs) | Rt(rt) | RnSP(src.GetBaseRegister())); \1756}1757#define DEFINE_ASM_STORE_FUNC(FN, OP_X, OP_W) \1758void Assembler::st##FN(const Register& rs, const MemOperand& src) { \1759VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1760ld##FN(rs, AppropriateZeroRegFor(rs), src); \1761}17621763ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(ATOMIC_MEMORY_LOAD_MODES,1764DEFINE_ASM_LOAD_FUNC)1765ATOMIC_MEMORY_SIMPLE_OPERATION_LIST(ATOMIC_MEMORY_STORE_MODES,1766DEFINE_ASM_STORE_FUNC)17671768#define DEFINE_ASM_SWP_FUNC(FN, OP_X, OP_W) \1769void Assembler::FN(const Register& rs, \1770const Register& rt, \1771const MemOperand& src) { \1772VIXL_ASSERT(CPUHas(CPUFeatures::kAtomics)); \1773VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0)); \1774AtomicMemoryOp op = rt.Is64Bits() ? OP_X : OP_W; \1775Emit(op | Rs(rs) | Rt(rt) | RnSP(src.GetBaseRegister())); \1776}17771778ATOMIC_MEMORY_LOAD_MODES(DEFINE_ASM_SWP_FUNC, swp, SWP)17791780#undef DEFINE_ASM_LOAD_FUNC1781#undef DEFINE_ASM_STORE_FUNC1782#undef DEFINE_ASM_SWP_FUNC178317841785void Assembler::ldaprb(const Register& rt, const MemOperand& src) {1786VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));1787VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1788AtomicMemoryOp op = LDAPRB;1789Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));1790}17911792void Assembler::ldapurb(const Register& rt, const MemOperand& src) {1793VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1794VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));17951796Instr base = RnSP(src.GetBaseRegister());1797int64_t offset = src.GetOffset();1798Emit(LDAPURB | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1799}18001801void Assembler::ldapursb(const Register& rt, const MemOperand& src) {1802VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1803VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));18041805Instr base = RnSP(src.GetBaseRegister());1806int64_t offset = src.GetOffset();1807Instr op = rt.Is64Bits() ? LDAPURSB_x : LDAPURSB_w;1808Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1809}18101811void Assembler::ldaprh(const Register& rt, const MemOperand& src) {1812VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));1813VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1814AtomicMemoryOp op = LDAPRH;1815Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));1816}18171818void Assembler::ldapurh(const Register& rt, const MemOperand& src) {1819VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1820VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));18211822Instr base = RnSP(src.GetBaseRegister());1823int64_t offset = src.GetOffset();1824Emit(LDAPURH | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1825}18261827void Assembler::ldapursh(const Register& rt, const MemOperand& src) {1828VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1829VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));18301831Instr base = RnSP(src.GetBaseRegister());1832int64_t offset = src.GetOffset();1833LoadStoreRCpcUnscaledOffsetOp op = rt.Is64Bits() ? LDAPURSH_x : LDAPURSH_w;1834Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1835}18361837void Assembler::ldapr(const Register& rt, const MemOperand& src) {1838VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc));1839VIXL_ASSERT(src.IsImmediateOffset() && (src.GetOffset() == 0));1840AtomicMemoryOp op = rt.Is64Bits() ? LDAPR_x : LDAPR_w;1841Emit(op | Rs(xzr) | Rt(rt) | RnSP(src.GetBaseRegister()));1842}18431844void Assembler::ldapur(const Register& rt, const MemOperand& src) {1845VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1846VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));18471848Instr base = RnSP(src.GetBaseRegister());1849int64_t offset = src.GetOffset();1850LoadStoreRCpcUnscaledOffsetOp op = rt.Is64Bits() ? LDAPUR_x : LDAPUR_w;1851Emit(op | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1852}18531854void Assembler::ldapursw(const Register& rt, const MemOperand& src) {1855VIXL_ASSERT(CPUHas(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm));1856VIXL_ASSERT(rt.Is64Bits());1857VIXL_ASSERT(src.IsImmediateOffset() && IsImmLSUnscaled(src.GetOffset()));18581859Instr base = RnSP(src.GetBaseRegister());1860int64_t offset = src.GetOffset();1861Emit(LDAPURSW | Rt(rt) | base | ImmLS(static_cast<int>(offset)));1862}18631864void Assembler::prfm(int op,1865const MemOperand& address,1866LoadStoreScalingOption option) {1867VIXL_ASSERT(option != RequireUnscaledOffset);1868VIXL_ASSERT(option != PreferUnscaledOffset);1869Prefetch(op, address, option);1870}18711872void Assembler::prfm(PrefetchOperation op,1873const MemOperand& address,1874LoadStoreScalingOption option) {1875// Passing unnamed values in 'op' is undefined behaviour in C++.1876VIXL_ASSERT(IsNamedPrefetchOperation(op));1877prfm(static_cast<int>(op), address, option);1878}187918801881void Assembler::prfum(int op,1882const MemOperand& address,1883LoadStoreScalingOption option) {1884VIXL_ASSERT(option != RequireScaledOffset);1885VIXL_ASSERT(option != PreferScaledOffset);1886Prefetch(op, address, option);1887}18881889void Assembler::prfum(PrefetchOperation op,1890const MemOperand& address,1891LoadStoreScalingOption option) {1892// Passing unnamed values in 'op' is undefined behaviour in C++.1893VIXL_ASSERT(IsNamedPrefetchOperation(op));1894prfum(static_cast<int>(op), address, option);1895}189618971898void Assembler::prfm(int op, RawLiteral* literal) {1899prfm(op, static_cast<int>(LinkAndGetWordOffsetTo(literal)));1900}19011902void Assembler::prfm(PrefetchOperation op, RawLiteral* literal) {1903// Passing unnamed values in 'op' is undefined behaviour in C++.1904VIXL_ASSERT(IsNamedPrefetchOperation(op));1905prfm(static_cast<int>(op), literal);1906}190719081909void Assembler::sys(int op1, int crn, int crm, int op2, const Register& xt) {1910VIXL_ASSERT(xt.Is64Bits());1911Emit(SYS | ImmSysOp1(op1) | CRn(crn) | CRm(crm) | ImmSysOp2(op2) | Rt(xt));1912}191319141915void Assembler::sys(int op, const Register& xt) {1916VIXL_ASSERT(xt.Is64Bits());1917Emit(SYS | SysOp(op) | Rt(xt));1918}191919201921void Assembler::dc(DataCacheOp op, const Register& rt) {1922if (op == CVAP) VIXL_ASSERT(CPUHas(CPUFeatures::kDCPoP));1923if (op == CVADP) VIXL_ASSERT(CPUHas(CPUFeatures::kDCCVADP));1924sys(op, rt);1925}192619271928void Assembler::ic(InstructionCacheOp op, const Register& rt) {1929VIXL_ASSERT(op == IVAU);1930sys(op, rt);1931}193219331934void Assembler::hint(SystemHint code) { hint(static_cast<int>(code)); }193519361937void Assembler::hint(int imm7) {1938VIXL_ASSERT(IsUint7(imm7));1939Emit(HINT | ImmHint(imm7) | Rt(xzr));1940}194119421943// MTE.19441945void Assembler::addg(const Register& xd,1946const Register& xn,1947int offset,1948int tag_offset) {1949VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));1950VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));19511952Emit(0x91800000 | RdSP(xd) | RnSP(xn) |1953ImmUnsignedField<21, 16>(offset / kMTETagGranuleInBytes) |1954ImmUnsignedField<13, 10>(tag_offset));1955}19561957void Assembler::gmi(const Register& xd,1958const Register& xn,1959const Register& xm) {1960VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));19611962Emit(0x9ac01400 | Rd(xd) | RnSP(xn) | Rm(xm));1963}19641965void Assembler::irg(const Register& xd,1966const Register& xn,1967const Register& xm) {1968VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));19691970Emit(0x9ac01000 | RdSP(xd) | RnSP(xn) | Rm(xm));1971}19721973void Assembler::ldg(const Register& xt, const MemOperand& addr) {1974VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));1975VIXL_ASSERT(addr.IsImmediateOffset());1976int offset = static_cast<int>(addr.GetOffset());1977VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));19781979Emit(0xd9600000 | Rt(xt) | RnSP(addr.GetBaseRegister()) |1980ImmField<20, 12>(offset / static_cast<int>(kMTETagGranuleInBytes)));1981}19821983void Assembler::StoreTagHelper(const Register& xt,1984const MemOperand& addr,1985Instr op) {1986int offset = static_cast<int>(addr.GetOffset());1987VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));19881989Instr addr_mode;1990if (addr.IsImmediateOffset()) {1991addr_mode = 2;1992} else if (addr.IsImmediatePreIndex()) {1993addr_mode = 3;1994} else {1995VIXL_ASSERT(addr.IsImmediatePostIndex());1996addr_mode = 1;1997}19981999Emit(op | RdSP(xt) | RnSP(addr.GetBaseRegister()) | (addr_mode << 10) |2000ImmField<20, 12>(offset / static_cast<int>(kMTETagGranuleInBytes)));2001}20022003void Assembler::st2g(const Register& xt, const MemOperand& addr) {2004VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2005StoreTagHelper(xt, addr, 0xd9a00000);2006}20072008void Assembler::stg(const Register& xt, const MemOperand& addr) {2009VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2010StoreTagHelper(xt, addr, 0xd9200000);2011}20122013void Assembler::stgp(const Register& xt1,2014const Register& xt2,2015const MemOperand& addr) {2016VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2017int offset = static_cast<int>(addr.GetOffset());2018VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));20192020Instr addr_mode;2021if (addr.IsImmediateOffset()) {2022addr_mode = 2;2023} else if (addr.IsImmediatePreIndex()) {2024addr_mode = 3;2025} else {2026VIXL_ASSERT(addr.IsImmediatePostIndex());2027addr_mode = 1;2028}20292030Emit(0x68000000 | RnSP(addr.GetBaseRegister()) | (addr_mode << 23) |2031ImmField<21, 15>(offset / static_cast<int>(kMTETagGranuleInBytes)) |2032Rt2(xt2) | Rt(xt1));2033}20342035void Assembler::stz2g(const Register& xt, const MemOperand& addr) {2036VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2037StoreTagHelper(xt, addr, 0xd9e00000);2038}20392040void Assembler::stzg(const Register& xt, const MemOperand& addr) {2041VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2042StoreTagHelper(xt, addr, 0xd9600000);2043}20442045void Assembler::subg(const Register& xd,2046const Register& xn,2047int offset,2048int tag_offset) {2049VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));2050VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));20512052Emit(0xd1800000 | RdSP(xd) | RnSP(xn) |2053ImmUnsignedField<21, 16>(offset / kMTETagGranuleInBytes) |2054ImmUnsignedField<13, 10>(tag_offset));2055}20562057void Assembler::subp(const Register& xd,2058const Register& xn,2059const Register& xm) {2060VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));20612062Emit(0x9ac00000 | Rd(xd) | RnSP(xn) | RmSP(xm));2063}20642065void Assembler::subps(const Register& xd,2066const Register& xn,2067const Register& xm) {2068VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));20692070Emit(0xbac00000 | Rd(xd) | RnSP(xn) | RmSP(xm));2071}20722073void Assembler::cpye(const Register& rd,2074const Register& rs,2075const Register& rn) {2076VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2077VIXL_ASSERT(!AreAliased(rd, rn, rs));2078VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());20792080Emit(0x1d800400 | Rd(rd) | Rn(rn) | Rs(rs));2081}20822083void Assembler::cpyen(const Register& rd,2084const Register& rs,2085const Register& rn) {2086VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2087VIXL_ASSERT(!AreAliased(rd, rn, rs));2088VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());20892090Emit(0x1d80c400 | Rd(rd) | Rn(rn) | Rs(rs));2091}20922093void Assembler::cpyern(const Register& rd,2094const Register& rs,2095const Register& rn) {2096VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2097VIXL_ASSERT(!AreAliased(rd, rn, rs));2098VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());20992100Emit(0x1d808400 | Rd(rd) | Rn(rn) | Rs(rs));2101}21022103void Assembler::cpyewn(const Register& rd,2104const Register& rs,2105const Register& rn) {2106VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2107VIXL_ASSERT(!AreAliased(rd, rn, rs));2108VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21092110Emit(0x1d804400 | Rd(rd) | Rn(rn) | Rs(rs));2111}21122113void Assembler::cpyfe(const Register& rd,2114const Register& rs,2115const Register& rn) {2116VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2117VIXL_ASSERT(!AreAliased(rd, rn, rs));2118VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21192120Emit(0x19800400 | Rd(rd) | Rn(rn) | Rs(rs));2121}21222123void Assembler::cpyfen(const Register& rd,2124const Register& rs,2125const Register& rn) {2126VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2127VIXL_ASSERT(!AreAliased(rd, rn, rs));2128VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21292130Emit(0x1980c400 | Rd(rd) | Rn(rn) | Rs(rs));2131}21322133void Assembler::cpyfern(const Register& rd,2134const Register& rs,2135const Register& rn) {2136VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2137VIXL_ASSERT(!AreAliased(rd, rn, rs));2138VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21392140Emit(0x19808400 | Rd(rd) | Rn(rn) | Rs(rs));2141}21422143void Assembler::cpyfewn(const Register& rd,2144const Register& rs,2145const Register& rn) {2146VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2147VIXL_ASSERT(!AreAliased(rd, rn, rs));2148VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21492150Emit(0x19804400 | Rd(rd) | Rn(rn) | Rs(rs));2151}21522153void Assembler::cpyfm(const Register& rd,2154const Register& rs,2155const Register& rn) {2156VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2157VIXL_ASSERT(!AreAliased(rd, rn, rs));2158VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21592160Emit(0x19400400 | Rd(rd) | Rn(rn) | Rs(rs));2161}21622163void Assembler::cpyfmn(const Register& rd,2164const Register& rs,2165const Register& rn) {2166VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2167VIXL_ASSERT(!AreAliased(rd, rn, rs));2168VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21692170Emit(0x1940c400 | Rd(rd) | Rn(rn) | Rs(rs));2171}21722173void Assembler::cpyfmrn(const Register& rd,2174const Register& rs,2175const Register& rn) {2176VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2177VIXL_ASSERT(!AreAliased(rd, rn, rs));2178VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21792180Emit(0x19408400 | Rd(rd) | Rn(rn) | Rs(rs));2181}21822183void Assembler::cpyfmwn(const Register& rd,2184const Register& rs,2185const Register& rn) {2186VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2187VIXL_ASSERT(!AreAliased(rd, rn, rs));2188VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21892190Emit(0x19404400 | Rd(rd) | Rn(rn) | Rs(rs));2191}21922193void Assembler::cpyfp(const Register& rd,2194const Register& rs,2195const Register& rn) {2196VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2197VIXL_ASSERT(!AreAliased(rd, rn, rs));2198VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());21992200Emit(0x19000400 | Rd(rd) | Rn(rn) | Rs(rs));2201}22022203void Assembler::cpyfpn(const Register& rd,2204const Register& rs,2205const Register& rn) {2206VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2207VIXL_ASSERT(!AreAliased(rd, rn, rs));2208VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22092210Emit(0x1900c400 | Rd(rd) | Rn(rn) | Rs(rs));2211}22122213void Assembler::cpyfprn(const Register& rd,2214const Register& rs,2215const Register& rn) {2216VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2217VIXL_ASSERT(!AreAliased(rd, rn, rs));2218VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22192220Emit(0x19008400 | Rd(rd) | Rn(rn) | Rs(rs));2221}22222223void Assembler::cpyfpwn(const Register& rd,2224const Register& rs,2225const Register& rn) {2226VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2227VIXL_ASSERT(!AreAliased(rd, rn, rs));2228VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22292230Emit(0x19004400 | Rd(rd) | Rn(rn) | Rs(rs));2231}22322233void Assembler::cpym(const Register& rd,2234const Register& rs,2235const Register& rn) {2236VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2237VIXL_ASSERT(!AreAliased(rd, rn, rs));2238VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22392240Emit(0x1d400400 | Rd(rd) | Rn(rn) | Rs(rs));2241}22422243void Assembler::cpymn(const Register& rd,2244const Register& rs,2245const Register& rn) {2246VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2247VIXL_ASSERT(!AreAliased(rd, rn, rs));2248VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22492250Emit(0x1d40c400 | Rd(rd) | Rn(rn) | Rs(rs));2251}22522253void Assembler::cpymrn(const Register& rd,2254const Register& rs,2255const Register& rn) {2256VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2257VIXL_ASSERT(!AreAliased(rd, rn, rs));2258VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22592260Emit(0x1d408400 | Rd(rd) | Rn(rn) | Rs(rs));2261}22622263void Assembler::cpymwn(const Register& rd,2264const Register& rs,2265const Register& rn) {2266VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2267VIXL_ASSERT(!AreAliased(rd, rn, rs));2268VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22692270Emit(0x1d404400 | Rd(rd) | Rn(rn) | Rs(rs));2271}22722273void Assembler::cpyp(const Register& rd,2274const Register& rs,2275const Register& rn) {2276VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2277VIXL_ASSERT(!AreAliased(rd, rn, rs));2278VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22792280Emit(0x1d000400 | Rd(rd) | Rn(rn) | Rs(rs));2281}22822283void Assembler::cpypn(const Register& rd,2284const Register& rs,2285const Register& rn) {2286VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2287VIXL_ASSERT(!AreAliased(rd, rn, rs));2288VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22892290Emit(0x1d00c400 | Rd(rd) | Rn(rn) | Rs(rs));2291}22922293void Assembler::cpyprn(const Register& rd,2294const Register& rs,2295const Register& rn) {2296VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2297VIXL_ASSERT(!AreAliased(rd, rn, rs));2298VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());22992300Emit(0x1d008400 | Rd(rd) | Rn(rn) | Rs(rs));2301}23022303void Assembler::cpypwn(const Register& rd,2304const Register& rs,2305const Register& rn) {2306VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2307VIXL_ASSERT(!AreAliased(rd, rn, rs));2308VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());23092310Emit(0x1d004400 | Rd(rd) | Rn(rn) | Rs(rs));2311}23122313void Assembler::sete(const Register& rd,2314const Register& rn,2315const Register& rs) {2316VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2317VIXL_ASSERT(!AreAliased(rd, rn, rs));2318VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23192320Emit(0x19c08400 | Rd(rd) | Rn(rn) | Rs(rs));2321}23222323void Assembler::seten(const Register& rd,2324const Register& rn,2325const Register& rs) {2326VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2327VIXL_ASSERT(!AreAliased(rd, rn, rs));2328VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23292330Emit(0x19c0a400 | Rd(rd) | Rn(rn) | Rs(rs));2331}23322333void Assembler::setge(const Register& rd,2334const Register& rn,2335const Register& rs) {2336VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2337VIXL_ASSERT(!AreAliased(rd, rn, rs));2338VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23392340Emit(0x1dc08400 | Rd(rd) | Rn(rn) | Rs(rs));2341}23422343void Assembler::setgen(const Register& rd,2344const Register& rn,2345const Register& rs) {2346VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2347VIXL_ASSERT(!AreAliased(rd, rn, rs));2348VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23492350Emit(0x1dc0a400 | Rd(rd) | Rn(rn) | Rs(rs));2351}23522353void Assembler::setgm(const Register& rd,2354const Register& rn,2355const Register& rs) {2356VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2357VIXL_ASSERT(!AreAliased(rd, rn, rs));2358VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23592360Emit(0x1dc04400 | Rd(rd) | Rn(rn) | Rs(rs));2361}23622363void Assembler::setgmn(const Register& rd,2364const Register& rn,2365const Register& rs) {2366VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2367VIXL_ASSERT(!AreAliased(rd, rn, rs));2368VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23692370Emit(0x1dc06400 | Rd(rd) | Rn(rn) | Rs(rs));2371}23722373void Assembler::setgp(const Register& rd,2374const Register& rn,2375const Register& rs) {2376VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2377VIXL_ASSERT(!AreAliased(rd, rn, rs));2378VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23792380Emit(0x1dc00400 | Rd(rd) | Rn(rn) | Rs(rs));2381}23822383void Assembler::setgpn(const Register& rd,2384const Register& rn,2385const Register& rs) {2386VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2387VIXL_ASSERT(!AreAliased(rd, rn, rs));2388VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23892390Emit(0x1dc02400 | Rd(rd) | Rn(rn) | Rs(rs));2391}23922393void Assembler::setm(const Register& rd,2394const Register& rn,2395const Register& rs) {2396VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2397VIXL_ASSERT(!AreAliased(rd, rn, rs));2398VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());23992400Emit(0x19c04400 | Rd(rd) | Rn(rn) | Rs(rs));2401}24022403void Assembler::setmn(const Register& rd,2404const Register& rn,2405const Register& rs) {2406VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2407VIXL_ASSERT(!AreAliased(rd, rn, rs));2408VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());24092410Emit(0x19c06400 | Rd(rd) | Rn(rn) | Rs(rs));2411}24122413void Assembler::setp(const Register& rd,2414const Register& rn,2415const Register& rs) {2416VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2417VIXL_ASSERT(!AreAliased(rd, rn, rs));2418VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());24192420Emit(0x19c00400 | Rd(rd) | Rn(rn) | Rs(rs));2421}24222423void Assembler::setpn(const Register& rd,2424const Register& rn,2425const Register& rs) {2426VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));2427VIXL_ASSERT(!AreAliased(rd, rn, rs));2428VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());24292430Emit(0x19c02400 | Rd(rd) | Rn(rn) | Rs(rs));2431}24322433void Assembler::abs(const Register& rd, const Register& rn) {2434VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));2435VIXL_ASSERT(rd.IsSameSizeAndType(rn));24362437Emit(0x5ac02000 | SF(rd) | Rd(rd) | Rn(rn));2438}24392440void Assembler::cnt(const Register& rd, const Register& rn) {2441VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));2442VIXL_ASSERT(rd.IsSameSizeAndType(rn));24432444Emit(0x5ac01c00 | SF(rd) | Rd(rd) | Rn(rn));2445}24462447void Assembler::ctz(const Register& rd, const Register& rn) {2448VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));2449VIXL_ASSERT(rd.IsSameSizeAndType(rn));24502451Emit(0x5ac01800 | SF(rd) | Rd(rd) | Rn(rn));2452}24532454#define MINMAX(V) \2455V(smax, 0x11c00000, 0x1ac06000, true) \2456V(smin, 0x11c80000, 0x1ac06800, true) \2457V(umax, 0x11c40000, 0x1ac06400, false) \2458V(umin, 0x11cc0000, 0x1ac06c00, false)24592460#define VIXL_DEFINE_ASM_FUNC(FN, IMMOP, REGOP, SIGNED) \2461void Assembler::FN(const Register& rd, \2462const Register& rn, \2463const Operand& op) { \2464VIXL_ASSERT(rd.IsSameSizeAndType(rn)); \2465Instr i = SF(rd) | Rd(rd) | Rn(rn); \2466if (op.IsImmediate()) { \2467int64_t imm = op.GetImmediate(); \2468i |= SIGNED ? ImmField<17, 10>(imm) : ImmUnsignedField<17, 10>(imm); \2469Emit(IMMOP | i); \2470} else { \2471VIXL_ASSERT(op.IsPlainRegister()); \2472VIXL_ASSERT(op.GetRegister().IsSameSizeAndType(rd)); \2473Emit(REGOP | i | Rm(op.GetRegister())); \2474} \2475}2476MINMAX(VIXL_DEFINE_ASM_FUNC)2477#undef VIXL_DEFINE_ASM_FUNC24782479// NEON structure loads and stores.2480Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) {2481Instr addr_field = RnSP(addr.GetBaseRegister());24822483if (addr.IsPostIndex()) {2484VIXL_STATIC_ASSERT(NEONLoadStoreMultiStructPostIndex ==2485static_cast<NEONLoadStoreMultiStructPostIndexOp>(2486NEONLoadStoreSingleStructPostIndex));24872488addr_field |= NEONLoadStoreMultiStructPostIndex;2489if (addr.GetOffset() == 0) {2490addr_field |= RmNot31(addr.GetRegisterOffset());2491} else {2492// The immediate post index addressing mode is indicated by rm = 31.2493// The immediate is implied by the number of vector registers used.2494addr_field |= (0x1f << Rm_offset);2495}2496} else {2497VIXL_ASSERT(addr.IsImmediateOffset() && (addr.GetOffset() == 0));2498}2499return addr_field;2500}25012502void Assembler::LoadStoreStructVerify(const VRegister& vt,2503const MemOperand& addr,2504Instr op) {2505#ifdef VIXL_DEBUG2506// Assert that addressing mode is either offset (with immediate 0), post2507// index by immediate of the size of the register list, or post index by a2508// value in a core register.2509VIXL_ASSERT(vt.HasSize() && vt.HasLaneSize());2510if (addr.IsImmediateOffset()) {2511VIXL_ASSERT(addr.GetOffset() == 0);2512} else {2513int offset = vt.GetSizeInBytes();2514switch (op) {2515case NEON_LD1_1v:2516case NEON_ST1_1v:2517offset *= 1;2518break;2519case NEONLoadStoreSingleStructLoad1:2520case NEONLoadStoreSingleStructStore1:2521case NEON_LD1R:2522offset = (offset / vt.GetLanes()) * 1;2523break;25242525case NEON_LD1_2v:2526case NEON_ST1_2v:2527case NEON_LD2:2528case NEON_ST2:2529offset *= 2;2530break;2531case NEONLoadStoreSingleStructLoad2:2532case NEONLoadStoreSingleStructStore2:2533case NEON_LD2R:2534offset = (offset / vt.GetLanes()) * 2;2535break;25362537case NEON_LD1_3v:2538case NEON_ST1_3v:2539case NEON_LD3:2540case NEON_ST3:2541offset *= 3;2542break;2543case NEONLoadStoreSingleStructLoad3:2544case NEONLoadStoreSingleStructStore3:2545case NEON_LD3R:2546offset = (offset / vt.GetLanes()) * 3;2547break;25482549case NEON_LD1_4v:2550case NEON_ST1_4v:2551case NEON_LD4:2552case NEON_ST4:2553offset *= 4;2554break;2555case NEONLoadStoreSingleStructLoad4:2556case NEONLoadStoreSingleStructStore4:2557case NEON_LD4R:2558offset = (offset / vt.GetLanes()) * 4;2559break;2560default:2561VIXL_UNREACHABLE();2562}2563VIXL_ASSERT(!addr.GetRegisterOffset().Is(NoReg) ||2564addr.GetOffset() == offset);2565}2566#else2567USE(vt, addr, op);2568#endif2569}25702571void Assembler::LoadStoreStruct(const VRegister& vt,2572const MemOperand& addr,2573NEONLoadStoreMultiStructOp op) {2574LoadStoreStructVerify(vt, addr, op);2575VIXL_ASSERT(vt.IsVector() || vt.Is1D());2576Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));2577}257825792580void Assembler::LoadStoreStructSingleAllLanes(const VRegister& vt,2581const MemOperand& addr,2582NEONLoadStoreSingleStructOp op) {2583LoadStoreStructVerify(vt, addr, op);2584Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt));2585}258625872588void Assembler::ld1(const VRegister& vt, const MemOperand& src) {2589VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2590LoadStoreStruct(vt, src, NEON_LD1_1v);2591}259225932594void Assembler::ld1(const VRegister& vt,2595const VRegister& vt2,2596const MemOperand& src) {2597USE(vt2);2598VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2599VIXL_ASSERT(AreSameFormat(vt, vt2));2600VIXL_ASSERT(AreConsecutive(vt, vt2));2601LoadStoreStruct(vt, src, NEON_LD1_2v);2602}260326042605void Assembler::ld1(const VRegister& vt,2606const VRegister& vt2,2607const VRegister& vt3,2608const MemOperand& src) {2609USE(vt2, vt3);2610VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2611VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2612VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2613LoadStoreStruct(vt, src, NEON_LD1_3v);2614}261526162617void Assembler::ld1(const VRegister& vt,2618const VRegister& vt2,2619const VRegister& vt3,2620const VRegister& vt4,2621const MemOperand& src) {2622USE(vt2, vt3, vt4);2623VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2624VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2625VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2626LoadStoreStruct(vt, src, NEON_LD1_4v);2627}262826292630void Assembler::ld2(const VRegister& vt,2631const VRegister& vt2,2632const MemOperand& src) {2633USE(vt2);2634VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2635VIXL_ASSERT(AreSameFormat(vt, vt2));2636VIXL_ASSERT(AreConsecutive(vt, vt2));2637LoadStoreStruct(vt, src, NEON_LD2);2638}263926402641void Assembler::ld2(const VRegister& vt,2642const VRegister& vt2,2643int lane,2644const MemOperand& src) {2645USE(vt2);2646VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2647VIXL_ASSERT(AreSameFormat(vt, vt2));2648VIXL_ASSERT(AreConsecutive(vt, vt2));2649LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad2);2650}265126522653void Assembler::ld2r(const VRegister& vt,2654const VRegister& vt2,2655const MemOperand& src) {2656USE(vt2);2657VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2658VIXL_ASSERT(AreSameFormat(vt, vt2));2659VIXL_ASSERT(AreConsecutive(vt, vt2));2660LoadStoreStructSingleAllLanes(vt, src, NEON_LD2R);2661}266226632664void Assembler::ld3(const VRegister& vt,2665const VRegister& vt2,2666const VRegister& vt3,2667const MemOperand& src) {2668USE(vt2, vt3);2669VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2670VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2671VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2672LoadStoreStruct(vt, src, NEON_LD3);2673}267426752676void Assembler::ld3(const VRegister& vt,2677const VRegister& vt2,2678const VRegister& vt3,2679int lane,2680const MemOperand& src) {2681USE(vt2, vt3);2682VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2683VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2684VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2685LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad3);2686}268726882689void Assembler::ld3r(const VRegister& vt,2690const VRegister& vt2,2691const VRegister& vt3,2692const MemOperand& src) {2693USE(vt2, vt3);2694VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2695VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2696VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2697LoadStoreStructSingleAllLanes(vt, src, NEON_LD3R);2698}269927002701void Assembler::ld4(const VRegister& vt,2702const VRegister& vt2,2703const VRegister& vt3,2704const VRegister& vt4,2705const MemOperand& src) {2706USE(vt2, vt3, vt4);2707VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2708VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2709VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2710LoadStoreStruct(vt, src, NEON_LD4);2711}271227132714void Assembler::ld4(const VRegister& vt,2715const VRegister& vt2,2716const VRegister& vt3,2717const VRegister& vt4,2718int lane,2719const MemOperand& src) {2720USE(vt2, vt3, vt4);2721VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2722VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2723VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2724LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad4);2725}272627272728void Assembler::ld4r(const VRegister& vt,2729const VRegister& vt2,2730const VRegister& vt3,2731const VRegister& vt4,2732const MemOperand& src) {2733USE(vt2, vt3, vt4);2734VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2735VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2736VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2737LoadStoreStructSingleAllLanes(vt, src, NEON_LD4R);2738}273927402741void Assembler::st1(const VRegister& vt, const MemOperand& src) {2742VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2743LoadStoreStruct(vt, src, NEON_ST1_1v);2744}274527462747void Assembler::st1(const VRegister& vt,2748const VRegister& vt2,2749const MemOperand& src) {2750USE(vt2);2751VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2752VIXL_ASSERT(AreSameFormat(vt, vt2));2753VIXL_ASSERT(AreConsecutive(vt, vt2));2754LoadStoreStruct(vt, src, NEON_ST1_2v);2755}275627572758void Assembler::st1(const VRegister& vt,2759const VRegister& vt2,2760const VRegister& vt3,2761const MemOperand& src) {2762USE(vt2, vt3);2763VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2764VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2765VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2766LoadStoreStruct(vt, src, NEON_ST1_3v);2767}276827692770void Assembler::st1(const VRegister& vt,2771const VRegister& vt2,2772const VRegister& vt3,2773const VRegister& vt4,2774const MemOperand& src) {2775USE(vt2, vt3, vt4);2776VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2777VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2778VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2779LoadStoreStruct(vt, src, NEON_ST1_4v);2780}278127822783void Assembler::st2(const VRegister& vt,2784const VRegister& vt2,2785const MemOperand& dst) {2786USE(vt2);2787VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2788VIXL_ASSERT(AreSameFormat(vt, vt2));2789VIXL_ASSERT(AreConsecutive(vt, vt2));2790LoadStoreStruct(vt, dst, NEON_ST2);2791}279227932794void Assembler::st2(const VRegister& vt,2795const VRegister& vt2,2796int lane,2797const MemOperand& dst) {2798USE(vt2);2799VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2800VIXL_ASSERT(AreSameFormat(vt, vt2));2801VIXL_ASSERT(AreConsecutive(vt, vt2));2802LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore2);2803}280428052806void Assembler::st3(const VRegister& vt,2807const VRegister& vt2,2808const VRegister& vt3,2809const MemOperand& dst) {2810USE(vt2, vt3);2811VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2812VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2813VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2814LoadStoreStruct(vt, dst, NEON_ST3);2815}281628172818void Assembler::st3(const VRegister& vt,2819const VRegister& vt2,2820const VRegister& vt3,2821int lane,2822const MemOperand& dst) {2823USE(vt2, vt3);2824VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2825VIXL_ASSERT(AreSameFormat(vt, vt2, vt3));2826VIXL_ASSERT(AreConsecutive(vt, vt2, vt3));2827LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore3);2828}282928302831void Assembler::st4(const VRegister& vt,2832const VRegister& vt2,2833const VRegister& vt3,2834const VRegister& vt4,2835const MemOperand& dst) {2836USE(vt2, vt3, vt4);2837VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2838VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2839VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2840LoadStoreStruct(vt, dst, NEON_ST4);2841}284228432844void Assembler::st4(const VRegister& vt,2845const VRegister& vt2,2846const VRegister& vt3,2847const VRegister& vt4,2848int lane,2849const MemOperand& dst) {2850USE(vt2, vt3, vt4);2851VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2852VIXL_ASSERT(AreSameFormat(vt, vt2, vt3, vt4));2853VIXL_ASSERT(AreConsecutive(vt, vt2, vt3, vt4));2854LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore4);2855}285628572858void Assembler::LoadStoreStructSingle(const VRegister& vt,2859uint32_t lane,2860const MemOperand& addr,2861NEONLoadStoreSingleStructOp op) {2862LoadStoreStructVerify(vt, addr, op);28632864// We support vt arguments of the form vt.VxT() or vt.T(), where x is the2865// number of lanes, and T is b, h, s or d.2866unsigned lane_size = vt.GetLaneSizeInBytes();2867VIXL_ASSERT(lane_size > 0);2868VIXL_ASSERT(lane < (kQRegSizeInBytes / lane_size));28692870// Lane size is encoded in the opcode field. Lane index is encoded in the Q,2871// S and size fields.2872lane *= lane_size;2873if (lane_size == 8) lane++;28742875Instr size = (lane << NEONLSSize_offset) & NEONLSSize_mask;2876Instr s = (lane << (NEONS_offset - 2)) & NEONS_mask;2877Instr q = (lane << (NEONQ_offset - 3)) & NEONQ_mask;28782879Instr instr = op;2880switch (lane_size) {2881case 1:2882instr |= NEONLoadStoreSingle_b;2883break;2884case 2:2885instr |= NEONLoadStoreSingle_h;2886break;2887case 4:2888instr |= NEONLoadStoreSingle_s;2889break;2890default:2891VIXL_ASSERT(lane_size == 8);2892instr |= NEONLoadStoreSingle_d;2893}28942895Emit(instr | LoadStoreStructAddrModeField(addr) | q | size | s | Rt(vt));2896}289728982899void Assembler::ld1(const VRegister& vt, int lane, const MemOperand& src) {2900VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2901LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad1);2902}290329042905void Assembler::ld1r(const VRegister& vt, const MemOperand& src) {2906VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2907LoadStoreStructSingleAllLanes(vt, src, NEON_LD1R);2908}290929102911void Assembler::st1(const VRegister& vt, int lane, const MemOperand& dst) {2912VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2913LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore1);2914}29152916void Assembler::pmull(const VRegister& vd,2917const VRegister& vn,2918const VRegister& vm) {2919VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2920VIXL_ASSERT(AreSameFormat(vn, vm));2921VIXL_ASSERT((vn.Is8B() && vd.Is8H()) || (vn.Is1D() && vd.Is1Q()));2922VIXL_ASSERT(CPUHas(CPUFeatures::kPmull1Q) || vd.Is8H());2923Emit(VFormat(vn) | NEON_PMULL | Rm(vm) | Rn(vn) | Rd(vd));2924}29252926void Assembler::pmull2(const VRegister& vd,2927const VRegister& vn,2928const VRegister& vm) {2929VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));2930VIXL_ASSERT(AreSameFormat(vn, vm));2931VIXL_ASSERT((vn.Is16B() && vd.Is8H()) || (vn.Is2D() && vd.Is1Q()));2932VIXL_ASSERT(CPUHas(CPUFeatures::kPmull1Q) || vd.Is8H());2933Emit(VFormat(vn) | NEON_PMULL2 | Rm(vm) | Rn(vn) | Rd(vd));2934}29352936void Assembler::NEON3DifferentL(const VRegister& vd,2937const VRegister& vn,2938const VRegister& vm,2939NEON3DifferentOp vop) {2940VIXL_ASSERT(AreSameFormat(vn, vm));2941VIXL_ASSERT((vn.Is1H() && vd.Is1S()) || (vn.Is1S() && vd.Is1D()) ||2942(vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||2943(vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||2944(vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));2945Instr format, op = vop;2946if (vd.IsScalar()) {2947op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);2948format = SFormat(vn);2949} else {2950format = VFormat(vn);2951}2952Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));2953}295429552956void Assembler::NEON3DifferentW(const VRegister& vd,2957const VRegister& vn,2958const VRegister& vm,2959NEON3DifferentOp vop) {2960VIXL_ASSERT(AreSameFormat(vd, vn));2961VIXL_ASSERT((vm.Is8B() && vd.Is8H()) || (vm.Is4H() && vd.Is4S()) ||2962(vm.Is2S() && vd.Is2D()) || (vm.Is16B() && vd.Is8H()) ||2963(vm.Is8H() && vd.Is4S()) || (vm.Is4S() && vd.Is2D()));2964Emit(VFormat(vm) | vop | Rm(vm) | Rn(vn) | Rd(vd));2965}296629672968void Assembler::NEON3DifferentHN(const VRegister& vd,2969const VRegister& vn,2970const VRegister& vm,2971NEON3DifferentOp vop) {2972VIXL_ASSERT(AreSameFormat(vm, vn));2973VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||2974(vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||2975(vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));2976Emit(VFormat(vd) | vop | Rm(vm) | Rn(vn) | Rd(vd));2977}297829792980// clang-format off2981#define NEON_3DIFF_LONG_LIST(V) \2982V(saddl, NEON_SADDL, vn.IsVector() && vn.IsD()) \2983V(saddl2, NEON_SADDL2, vn.IsVector() && vn.IsQ()) \2984V(sabal, NEON_SABAL, vn.IsVector() && vn.IsD()) \2985V(sabal2, NEON_SABAL2, vn.IsVector() && vn.IsQ()) \2986V(uabal, NEON_UABAL, vn.IsVector() && vn.IsD()) \2987V(uabal2, NEON_UABAL2, vn.IsVector() && vn.IsQ()) \2988V(sabdl, NEON_SABDL, vn.IsVector() && vn.IsD()) \2989V(sabdl2, NEON_SABDL2, vn.IsVector() && vn.IsQ()) \2990V(uabdl, NEON_UABDL, vn.IsVector() && vn.IsD()) \2991V(uabdl2, NEON_UABDL2, vn.IsVector() && vn.IsQ()) \2992V(smlal, NEON_SMLAL, vn.IsVector() && vn.IsD()) \2993V(smlal2, NEON_SMLAL2, vn.IsVector() && vn.IsQ()) \2994V(umlal, NEON_UMLAL, vn.IsVector() && vn.IsD()) \2995V(umlal2, NEON_UMLAL2, vn.IsVector() && vn.IsQ()) \2996V(smlsl, NEON_SMLSL, vn.IsVector() && vn.IsD()) \2997V(smlsl2, NEON_SMLSL2, vn.IsVector() && vn.IsQ()) \2998V(umlsl, NEON_UMLSL, vn.IsVector() && vn.IsD()) \2999V(umlsl2, NEON_UMLSL2, vn.IsVector() && vn.IsQ()) \3000V(smull, NEON_SMULL, vn.IsVector() && vn.IsD()) \3001V(smull2, NEON_SMULL2, vn.IsVector() && vn.IsQ()) \3002V(umull, NEON_UMULL, vn.IsVector() && vn.IsD()) \3003V(umull2, NEON_UMULL2, vn.IsVector() && vn.IsQ()) \3004V(ssubl, NEON_SSUBL, vn.IsVector() && vn.IsD()) \3005V(ssubl2, NEON_SSUBL2, vn.IsVector() && vn.IsQ()) \3006V(uaddl, NEON_UADDL, vn.IsVector() && vn.IsD()) \3007V(uaddl2, NEON_UADDL2, vn.IsVector() && vn.IsQ()) \3008V(usubl, NEON_USUBL, vn.IsVector() && vn.IsD()) \3009V(usubl2, NEON_USUBL2, vn.IsVector() && vn.IsQ()) \3010V(sqdmlal, NEON_SQDMLAL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \3011V(sqdmlal2, NEON_SQDMLAL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \3012V(sqdmlsl, NEON_SQDMLSL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \3013V(sqdmlsl2, NEON_SQDMLSL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \3014V(sqdmull, NEON_SQDMULL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \3015V(sqdmull2, NEON_SQDMULL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \3016// clang-format on301730183019#define VIXL_DEFINE_ASM_FUNC(FN, OP, AS) \3020void Assembler::FN(const VRegister& vd, \3021const VRegister& vn, \3022const VRegister& vm) { \3023VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \3024VIXL_ASSERT(AS); \3025NEON3DifferentL(vd, vn, vm, OP); \3026}3027NEON_3DIFF_LONG_LIST(VIXL_DEFINE_ASM_FUNC)3028#undef VIXL_DEFINE_ASM_FUNC30293030// clang-format off3031#define NEON_3DIFF_HN_LIST(V) \3032V(addhn, NEON_ADDHN, vd.IsD()) \3033V(addhn2, NEON_ADDHN2, vd.IsQ()) \3034V(raddhn, NEON_RADDHN, vd.IsD()) \3035V(raddhn2, NEON_RADDHN2, vd.IsQ()) \3036V(subhn, NEON_SUBHN, vd.IsD()) \3037V(subhn2, NEON_SUBHN2, vd.IsQ()) \3038V(rsubhn, NEON_RSUBHN, vd.IsD()) \3039V(rsubhn2, NEON_RSUBHN2, vd.IsQ())3040// clang-format on30413042#define VIXL_DEFINE_ASM_FUNC(FN, OP, AS) \3043void Assembler::FN(const VRegister& vd, \3044const VRegister& vn, \3045const VRegister& vm) { \3046VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \3047VIXL_ASSERT(AS); \3048NEON3DifferentHN(vd, vn, vm, OP); \3049}3050NEON_3DIFF_HN_LIST(VIXL_DEFINE_ASM_FUNC)3051#undef VIXL_DEFINE_ASM_FUNC30523053void Assembler::uaddw(const VRegister& vd,3054const VRegister& vn,3055const VRegister& vm) {3056VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3057VIXL_ASSERT(vm.IsD());3058NEON3DifferentW(vd, vn, vm, NEON_UADDW);3059}306030613062void Assembler::uaddw2(const VRegister& vd,3063const VRegister& vn,3064const VRegister& vm) {3065VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3066VIXL_ASSERT(vm.IsQ());3067NEON3DifferentW(vd, vn, vm, NEON_UADDW2);3068}306930703071void Assembler::saddw(const VRegister& vd,3072const VRegister& vn,3073const VRegister& vm) {3074VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3075VIXL_ASSERT(vm.IsD());3076NEON3DifferentW(vd, vn, vm, NEON_SADDW);3077}307830793080void Assembler::saddw2(const VRegister& vd,3081const VRegister& vn,3082const VRegister& vm) {3083VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3084VIXL_ASSERT(vm.IsQ());3085NEON3DifferentW(vd, vn, vm, NEON_SADDW2);3086}308730883089void Assembler::usubw(const VRegister& vd,3090const VRegister& vn,3091const VRegister& vm) {3092VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3093VIXL_ASSERT(vm.IsD());3094NEON3DifferentW(vd, vn, vm, NEON_USUBW);3095}309630973098void Assembler::usubw2(const VRegister& vd,3099const VRegister& vn,3100const VRegister& vm) {3101VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3102VIXL_ASSERT(vm.IsQ());3103NEON3DifferentW(vd, vn, vm, NEON_USUBW2);3104}310531063107void Assembler::ssubw(const VRegister& vd,3108const VRegister& vn,3109const VRegister& vm) {3110VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3111VIXL_ASSERT(vm.IsD());3112NEON3DifferentW(vd, vn, vm, NEON_SSUBW);3113}311431153116void Assembler::ssubw2(const VRegister& vd,3117const VRegister& vn,3118const VRegister& vm) {3119VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3120VIXL_ASSERT(vm.IsQ());3121NEON3DifferentW(vd, vn, vm, NEON_SSUBW2);3122}312331243125void Assembler::mov(const Register& rd, const Register& rm) {3126// Moves involving the stack pointer are encoded as add immediate with3127// second operand of zero. Otherwise, orr with first operand zr is3128// used.3129if (rd.IsSP() || rm.IsSP()) {3130add(rd, rm, 0);3131} else {3132orr(rd, AppropriateZeroRegFor(rd), rm);3133}3134}31353136void Assembler::xpaclri() {3137VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3138Emit(XPACLRI);3139}31403141void Assembler::pacia1716() {3142VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3143Emit(PACIA1716);3144}31453146void Assembler::pacib1716() {3147VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3148Emit(PACIB1716);3149}31503151void Assembler::autia1716() {3152VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3153Emit(AUTIA1716);3154}31553156void Assembler::autib1716() {3157VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3158Emit(AUTIB1716);3159}31603161void Assembler::paciaz() {3162VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3163Emit(PACIAZ);3164}31653166void Assembler::pacibz() {3167VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3168Emit(PACIBZ);3169}31703171void Assembler::autiaz() {3172VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3173Emit(AUTIAZ);3174}31753176void Assembler::autibz() {3177VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3178Emit(AUTIBZ);3179}31803181void Assembler::paciasp() {3182VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3183Emit(PACIASP);3184}31853186void Assembler::pacibsp() {3187VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3188Emit(PACIBSP);3189}31903191void Assembler::autiasp() {3192VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3193Emit(AUTIASP);3194}31953196void Assembler::autibsp() {3197VIXL_ASSERT(CPUHas(CPUFeatures::kPAuth));3198Emit(AUTIBSP);3199}32003201void Assembler::bti(BranchTargetIdentifier id) {3202VIXL_ASSERT((id != EmitPACIASP) && (id != EmitPACIBSP)); // Not modes of Bti.3203VIXL_ASSERT(id != EmitBTI_none); // Always generate an instruction.3204VIXL_ASSERT(CPUHas(CPUFeatures::kBTI));3205hint(static_cast<SystemHint>(id));3206}32073208void Assembler::mvn(const Register& rd, const Operand& operand) {3209orn(rd, AppropriateZeroRegFor(rd), operand);3210}321132123213void Assembler::mrs(const Register& xt, SystemRegister sysreg) {3214VIXL_ASSERT(xt.Is64Bits());3215VIXL_ASSERT(CPUHas(sysreg));3216Emit(MRS | ImmSystemRegister(sysreg) | Rt(xt));3217}321832193220void Assembler::msr(SystemRegister sysreg, const Register& xt) {3221VIXL_ASSERT(xt.Is64Bits());3222VIXL_ASSERT(CPUHas(sysreg));3223Emit(MSR | Rt(xt) | ImmSystemRegister(sysreg));3224}322532263227void Assembler::cfinv() {3228VIXL_ASSERT(CPUHas(CPUFeatures::kFlagM));3229Emit(CFINV);3230}323132323233void Assembler::axflag() {3234VIXL_ASSERT(CPUHas(CPUFeatures::kAXFlag));3235Emit(AXFLAG);3236}323732383239void Assembler::xaflag() {3240VIXL_ASSERT(CPUHas(CPUFeatures::kAXFlag));3241Emit(XAFLAG);3242}324332443245void Assembler::clrex(int imm4) { Emit(CLREX | CRm(imm4)); }324632473248void Assembler::dmb(BarrierDomain domain, BarrierType type) {3249Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));3250}325132523253void Assembler::dsb(BarrierDomain domain, BarrierType type) {3254Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));3255}325632573258void Assembler::isb() {3259Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));3260}32613262void Assembler::esb() {3263VIXL_ASSERT(CPUHas(CPUFeatures::kRAS));3264hint(ESB);3265}32663267void Assembler::csdb() { hint(CSDB); }32683269void Assembler::fmov(const VRegister& vd, double imm) {3270VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3271if (vd.IsScalar()) {3272VIXL_ASSERT(vd.Is1D());3273Emit(FMOV_d_imm | Rd(vd) | ImmFP64(imm));3274} else {3275VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3276VIXL_ASSERT(vd.Is2D());3277Instr op = NEONModifiedImmediate_MOVI | NEONModifiedImmediateOpBit;3278Instr q = NEON_Q;3279uint32_t encoded_imm = FP64ToImm8(imm);3280Emit(q | op | ImmNEONabcdefgh(encoded_imm) | NEONCmode(0xf) | Rd(vd));3281}3282}328332843285void Assembler::fmov(const VRegister& vd, float imm) {3286VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3287if (vd.IsScalar()) {3288VIXL_ASSERT(vd.Is1S());3289Emit(FMOV_s_imm | Rd(vd) | ImmFP32(imm));3290} else {3291VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));3292VIXL_ASSERT(vd.Is2S() || vd.Is4S());3293Instr op = NEONModifiedImmediate_MOVI;3294Instr q = vd.Is4S() ? NEON_Q : 0;3295uint32_t encoded_imm = FP32ToImm8(imm);3296Emit(q | op | ImmNEONabcdefgh(encoded_imm) | NEONCmode(0xf) | Rd(vd));3297}3298}329933003301void Assembler::fmov(const VRegister& vd, Float16 imm) {3302VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3303if (vd.IsScalar()) {3304VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3305VIXL_ASSERT(vd.Is1H());3306Emit(FMOV_h_imm | Rd(vd) | ImmFP16(imm));3307} else {3308VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf));3309VIXL_ASSERT(vd.Is4H() || vd.Is8H());3310Instr q = vd.Is8H() ? NEON_Q : 0;3311uint32_t encoded_imm = FP16ToImm8(imm);3312Emit(q | NEONModifiedImmediate_FMOV | ImmNEONabcdefgh(encoded_imm) |3313NEONCmode(0xf) | Rd(vd));3314}3315}331633173318void Assembler::fmov(const Register& rd, const VRegister& vn) {3319VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3320VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3321VIXL_ASSERT((rd.GetSizeInBits() == vn.GetSizeInBits()) || vn.Is1H());3322FPIntegerConvertOp op;3323switch (vn.GetSizeInBits()) {3324case 16:3325VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3326op = rd.Is64Bits() ? FMOV_xh : FMOV_wh;3327break;3328case 32:3329op = FMOV_ws;3330break;3331default:3332op = FMOV_xd;3333}3334Emit(op | Rd(rd) | Rn(vn));3335}333633373338void Assembler::fmov(const VRegister& vd, const Register& rn) {3339VIXL_ASSERT(CPUHas(CPUFeatures::kFP) ||3340(vd.Is1D() && CPUHas(CPUFeatures::kNEON)));3341VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());3342VIXL_ASSERT((vd.GetSizeInBits() == rn.GetSizeInBits()) || vd.Is1H());3343FPIntegerConvertOp op;3344switch (vd.GetSizeInBits()) {3345case 16:3346VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3347op = rn.Is64Bits() ? FMOV_hx : FMOV_hw;3348break;3349case 32:3350op = FMOV_sw;3351break;3352default:3353op = FMOV_dx;3354}3355Emit(op | Rd(vd) | Rn(rn));3356}335733583359void Assembler::fmov(const VRegister& vd, const VRegister& vn) {3360VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3361if (vd.Is1H()) {3362VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3363}3364VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());3365VIXL_ASSERT(vd.IsSameFormat(vn));3366Emit(FPType(vd) | FMOV | Rd(vd) | Rn(vn));3367}336833693370void Assembler::fmov(const VRegister& vd, int index, const Register& rn) {3371VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kFP));3372VIXL_ASSERT((index == 1) && vd.Is1D() && rn.IsX());3373USE(index);3374Emit(FMOV_d1_x | Rd(vd) | Rn(rn));3375}337633773378void Assembler::fmov(const Register& rd, const VRegister& vn, int index) {3379VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kFP));3380VIXL_ASSERT((index == 1) && vn.Is1D() && rd.IsX());3381USE(index);3382Emit(FMOV_x_d1 | Rd(rd) | Rn(vn));3383}338433853386void Assembler::fmadd(const VRegister& vd,3387const VRegister& vn,3388const VRegister& vm,3389const VRegister& va) {3390VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3391FPDataProcessing3SourceOp op;3392if (vd.Is1H()) {3393VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3394op = FMADD_h;3395} else if (vd.Is1S()) {3396op = FMADD_s;3397} else {3398VIXL_ASSERT(vd.Is1D());3399op = FMADD_d;3400}3401FPDataProcessing3Source(vd, vn, vm, va, op);3402}340334043405void Assembler::fmsub(const VRegister& vd,3406const VRegister& vn,3407const VRegister& vm,3408const VRegister& va) {3409VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3410FPDataProcessing3SourceOp op;3411if (vd.Is1H()) {3412VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3413op = FMSUB_h;3414} else if (vd.Is1S()) {3415op = FMSUB_s;3416} else {3417VIXL_ASSERT(vd.Is1D());3418op = FMSUB_d;3419}3420FPDataProcessing3Source(vd, vn, vm, va, op);3421}342234233424void Assembler::fnmadd(const VRegister& vd,3425const VRegister& vn,3426const VRegister& vm,3427const VRegister& va) {3428VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3429FPDataProcessing3SourceOp op;3430if (vd.Is1H()) {3431VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3432op = FNMADD_h;3433} else if (vd.Is1S()) {3434op = FNMADD_s;3435} else {3436VIXL_ASSERT(vd.Is1D());3437op = FNMADD_d;3438}3439FPDataProcessing3Source(vd, vn, vm, va, op);3440}344134423443void Assembler::fnmsub(const VRegister& vd,3444const VRegister& vn,3445const VRegister& vm,3446const VRegister& va) {3447VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3448FPDataProcessing3SourceOp op;3449if (vd.Is1H()) {3450VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3451op = FNMSUB_h;3452} else if (vd.Is1S()) {3453op = FNMSUB_s;3454} else {3455VIXL_ASSERT(vd.Is1D());3456op = FNMSUB_d;3457}3458FPDataProcessing3Source(vd, vn, vm, va, op);3459}346034613462void Assembler::fnmul(const VRegister& vd,3463const VRegister& vn,3464const VRegister& vm) {3465VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3466VIXL_ASSERT(AreSameSizeAndType(vd, vn, vm));3467Instr op;3468if (vd.Is1H()) {3469VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3470op = FNMUL_h;3471} else if (vd.Is1S()) {3472op = FNMUL_s;3473} else {3474VIXL_ASSERT(vd.Is1D());3475op = FNMUL_d;3476}3477Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));3478}347934803481void Assembler::FPCompareMacro(const VRegister& vn,3482double value,3483FPTrapFlags trap) {3484USE(value);3485// Although the fcmp{e} instructions can strictly only take an immediate3486// value of +0.0, we don't need to check for -0.0 because the sign of 0.03487// doesn't affect the result of the comparison.3488VIXL_ASSERT(value == 0.0);3489VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3490Instr op = (trap == EnableTrap) ? FCMPE_zero : FCMP_zero;3491Emit(FPType(vn) | op | Rn(vn));3492}349334943495void Assembler::FPCompareMacro(const VRegister& vn,3496const VRegister& vm,3497FPTrapFlags trap) {3498VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3499VIXL_ASSERT(vn.IsSameSizeAndType(vm));3500Instr op = (trap == EnableTrap) ? FCMPE : FCMP;3501Emit(FPType(vn) | op | Rm(vm) | Rn(vn));3502}350335043505void Assembler::fcmp(const VRegister& vn, const VRegister& vm) {3506VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3507if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3508FPCompareMacro(vn, vm, DisableTrap);3509}351035113512void Assembler::fcmpe(const VRegister& vn, const VRegister& vm) {3513VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3514if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3515FPCompareMacro(vn, vm, EnableTrap);3516}351735183519void Assembler::fcmp(const VRegister& vn, double value) {3520VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3521if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3522FPCompareMacro(vn, value, DisableTrap);3523}352435253526void Assembler::fcmpe(const VRegister& vn, double value) {3527VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3528if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3529FPCompareMacro(vn, value, EnableTrap);3530}353135323533void Assembler::FPCCompareMacro(const VRegister& vn,3534const VRegister& vm,3535StatusFlags nzcv,3536Condition cond,3537FPTrapFlags trap) {3538VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3539VIXL_ASSERT(vn.IsSameSizeAndType(vm));3540Instr op = (trap == EnableTrap) ? FCCMPE : FCCMP;3541Emit(FPType(vn) | op | Rm(vm) | Cond(cond) | Rn(vn) | Nzcv(nzcv));3542}35433544void Assembler::fccmp(const VRegister& vn,3545const VRegister& vm,3546StatusFlags nzcv,3547Condition cond) {3548VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3549if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3550FPCCompareMacro(vn, vm, nzcv, cond, DisableTrap);3551}355235533554void Assembler::fccmpe(const VRegister& vn,3555const VRegister& vm,3556StatusFlags nzcv,3557Condition cond) {3558VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3559if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3560FPCCompareMacro(vn, vm, nzcv, cond, EnableTrap);3561}356235633564void Assembler::fcsel(const VRegister& vd,3565const VRegister& vn,3566const VRegister& vm,3567Condition cond) {3568VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3569if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3570VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());3571VIXL_ASSERT(AreSameFormat(vd, vn, vm));3572Emit(FPType(vd) | FCSEL | Rm(vm) | Cond(cond) | Rn(vn) | Rd(vd));3573}357435753576void Assembler::fcvt(const VRegister& vd, const VRegister& vn) {3577VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3578FPDataProcessing1SourceOp op;3579// The half-precision variants belong to base FP, and do not require kFPHalf.3580if (vd.Is1D()) {3581VIXL_ASSERT(vn.Is1S() || vn.Is1H());3582op = vn.Is1S() ? FCVT_ds : FCVT_dh;3583} else if (vd.Is1S()) {3584VIXL_ASSERT(vn.Is1D() || vn.Is1H());3585op = vn.Is1D() ? FCVT_sd : FCVT_sh;3586} else {3587VIXL_ASSERT(vd.Is1H());3588VIXL_ASSERT(vn.Is1D() || vn.Is1S());3589op = vn.Is1D() ? FCVT_hd : FCVT_hs;3590}3591FPDataProcessing1Source(vd, vn, op);3592}359335943595void Assembler::fcvtl(const VRegister& vd, const VRegister& vn) {3596VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3597VIXL_ASSERT((vd.Is4S() && vn.Is4H()) || (vd.Is2D() && vn.Is2S()));3598// The half-precision variants belong to base FP, and do not require kFPHalf.3599Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;3600Emit(format | NEON_FCVTL | Rn(vn) | Rd(vd));3601}360236033604void Assembler::fcvtl2(const VRegister& vd, const VRegister& vn) {3605VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3606VIXL_ASSERT((vd.Is4S() && vn.Is8H()) || (vd.Is2D() && vn.Is4S()));3607// The half-precision variants belong to base FP, and do not require kFPHalf.3608Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0;3609Emit(NEON_Q | format | NEON_FCVTL | Rn(vn) | Rd(vd));3610}361136123613void Assembler::fcvtn(const VRegister& vd, const VRegister& vn) {3614VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3615VIXL_ASSERT((vn.Is4S() && vd.Is4H()) || (vn.Is2D() && vd.Is2S()));3616// The half-precision variants belong to base FP, and do not require kFPHalf.3617Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;3618Emit(format | NEON_FCVTN | Rn(vn) | Rd(vd));3619}362036213622void Assembler::fcvtn2(const VRegister& vd, const VRegister& vn) {3623VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3624VIXL_ASSERT((vn.Is4S() && vd.Is8H()) || (vn.Is2D() && vd.Is4S()));3625// The half-precision variants belong to base FP, and do not require kFPHalf.3626Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0;3627Emit(NEON_Q | format | NEON_FCVTN | Rn(vn) | Rd(vd));3628}362936303631void Assembler::fcvtxn(const VRegister& vd, const VRegister& vn) {3632VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3633Instr format = 1 << NEONSize_offset;3634if (vd.IsScalar()) {3635VIXL_ASSERT(vd.Is1S() && vn.Is1D());3636Emit(format | NEON_FCVTXN_scalar | Rn(vn) | Rd(vd));3637} else {3638VIXL_ASSERT(vd.Is2S() && vn.Is2D());3639Emit(format | NEON_FCVTXN | Rn(vn) | Rd(vd));3640}3641}364236433644void Assembler::fcvtxn2(const VRegister& vd, const VRegister& vn) {3645VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3646VIXL_ASSERT(vd.Is4S() && vn.Is2D());3647Instr format = 1 << NEONSize_offset;3648Emit(NEON_Q | format | NEON_FCVTXN | Rn(vn) | Rd(vd));3649}36503651void Assembler::fjcvtzs(const Register& rd, const VRegister& vn) {3652VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kJSCVT));3653VIXL_ASSERT(rd.IsW() && vn.Is1D());3654Emit(FJCVTZS | Rn(vn) | Rd(rd));3655}365636573658void Assembler::NEONFPConvertToInt(const Register& rd,3659const VRegister& vn,3660Instr op) {3661Emit(SF(rd) | FPType(vn) | op | Rn(vn) | Rd(rd));3662}366336643665void Assembler::NEONFPConvertToInt(const VRegister& vd,3666const VRegister& vn,3667Instr op) {3668if (vn.IsScalar()) {3669VIXL_ASSERT((vd.Is1S() && vn.Is1S()) || (vd.Is1D() && vn.Is1D()));3670op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);3671}3672Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));3673}367436753676void Assembler::NEONFP16ConvertToInt(const VRegister& vd,3677const VRegister& vn,3678Instr op) {3679VIXL_ASSERT(AreSameFormat(vd, vn));3680VIXL_ASSERT(vn.IsLaneSizeH());3681if (vn.IsScalar()) {3682op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);3683} else if (vn.Is8H()) {3684op |= static_cast<Instr>(NEON_Q);3685}3686Emit(op | Rn(vn) | Rd(vd));3687}368836893690#define NEON_FP2REGMISC_FCVT_LIST(V) \3691V(fcvtnu, NEON_FCVTNU, FCVTNU) \3692V(fcvtns, NEON_FCVTNS, FCVTNS) \3693V(fcvtpu, NEON_FCVTPU, FCVTPU) \3694V(fcvtps, NEON_FCVTPS, FCVTPS) \3695V(fcvtmu, NEON_FCVTMU, FCVTMU) \3696V(fcvtms, NEON_FCVTMS, FCVTMS) \3697V(fcvtau, NEON_FCVTAU, FCVTAU) \3698V(fcvtas, NEON_FCVTAS, FCVTAS)36993700#define VIXL_DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \3701void Assembler::FN(const Register& rd, const VRegister& vn) { \3702VIXL_ASSERT(CPUHas(CPUFeatures::kFP)); \3703if (vn.IsH()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf)); \3704NEONFPConvertToInt(rd, vn, SCA_OP); \3705} \3706void Assembler::FN(const VRegister& vd, const VRegister& vn) { \3707VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON)); \3708if (vd.IsLaneSizeH()) { \3709VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \3710NEONFP16ConvertToInt(vd, vn, VEC_OP##_H); \3711} else { \3712NEONFPConvertToInt(vd, vn, VEC_OP); \3713} \3714}3715NEON_FP2REGMISC_FCVT_LIST(VIXL_DEFINE_ASM_FUNC)3716#undef VIXL_DEFINE_ASM_FUNC371737183719void Assembler::fcvtzs(const Register& rd, const VRegister& vn, int fbits) {3720VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3721if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3722VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3723VIXL_ASSERT((fbits >= 0) && (fbits <= rd.GetSizeInBits()));3724if (fbits == 0) {3725Emit(SF(rd) | FPType(vn) | FCVTZS | Rn(vn) | Rd(rd));3726} else {3727Emit(SF(rd) | FPType(vn) | FCVTZS_fixed | FPScale(64 - fbits) | Rn(vn) |3728Rd(rd));3729}3730}373137323733void Assembler::fcvtzs(const VRegister& vd, const VRegister& vn, int fbits) {3734// This form is a NEON scalar FP instruction.3735VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3736if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));3737VIXL_ASSERT(fbits >= 0);3738if (fbits == 0) {3739if (vd.IsLaneSizeH()) {3740NEONFP2RegMiscFP16(vd, vn, NEON_FCVTZS_H);3741} else {3742NEONFP2RegMisc(vd, vn, NEON_FCVTZS);3743}3744} else {3745VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||3746vd.Is1H() || vd.Is4H() || vd.Is8H());3747NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZS_imm);3748}3749}375037513752void Assembler::fcvtzu(const Register& rd, const VRegister& vn, int fbits) {3753VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3754if (vn.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3755VIXL_ASSERT(vn.Is1H() || vn.Is1S() || vn.Is1D());3756VIXL_ASSERT((fbits >= 0) && (fbits <= rd.GetSizeInBits()));3757if (fbits == 0) {3758Emit(SF(rd) | FPType(vn) | FCVTZU | Rn(vn) | Rd(rd));3759} else {3760Emit(SF(rd) | FPType(vn) | FCVTZU_fixed | FPScale(64 - fbits) | Rn(vn) |3761Rd(rd));3762}3763}376437653766void Assembler::fcvtzu(const VRegister& vd, const VRegister& vn, int fbits) {3767// This form is a NEON scalar FP instruction.3768VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3769if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));3770VIXL_ASSERT(fbits >= 0);3771if (fbits == 0) {3772if (vd.IsLaneSizeH()) {3773NEONFP2RegMiscFP16(vd, vn, NEON_FCVTZU_H);3774} else {3775NEONFP2RegMisc(vd, vn, NEON_FCVTZU);3776}3777} else {3778VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||3779vd.Is1H() || vd.Is4H() || vd.Is8H());3780NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZU_imm);3781}3782}37833784void Assembler::ucvtf(const VRegister& vd, const VRegister& vn, int fbits) {3785// This form is a NEON scalar FP instruction.3786VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3787if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));3788VIXL_ASSERT(fbits >= 0);3789if (fbits == 0) {3790if (vd.IsLaneSizeH()) {3791NEONFP2RegMiscFP16(vd, vn, NEON_UCVTF_H);3792} else {3793NEONFP2RegMisc(vd, vn, NEON_UCVTF);3794}3795} else {3796VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||3797vd.Is1H() || vd.Is4H() || vd.Is8H());3798NEONShiftRightImmediate(vd, vn, fbits, NEON_UCVTF_imm);3799}3800}38013802void Assembler::scvtf(const VRegister& vd, const VRegister& vn, int fbits) {3803// This form is a NEON scalar FP instruction.3804VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));3805if (vn.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));3806VIXL_ASSERT(fbits >= 0);3807if (fbits == 0) {3808if (vd.IsLaneSizeH()) {3809NEONFP2RegMiscFP16(vd, vn, NEON_SCVTF_H);3810} else {3811NEONFP2RegMisc(vd, vn, NEON_SCVTF);3812}3813} else {3814VIXL_ASSERT(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S() ||3815vd.Is1H() || vd.Is4H() || vd.Is8H());3816NEONShiftRightImmediate(vd, vn, fbits, NEON_SCVTF_imm);3817}3818}381938203821void Assembler::scvtf(const VRegister& vd, const Register& rn, int fbits) {3822VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3823if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3824VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());3825VIXL_ASSERT(fbits >= 0);3826if (fbits == 0) {3827Emit(SF(rn) | FPType(vd) | SCVTF | Rn(rn) | Rd(vd));3828} else {3829Emit(SF(rn) | FPType(vd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |3830Rd(vd));3831}3832}383338343835void Assembler::ucvtf(const VRegister& vd, const Register& rn, int fbits) {3836VIXL_ASSERT(CPUHas(CPUFeatures::kFP));3837if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf));3838VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());3839VIXL_ASSERT(fbits >= 0);3840if (fbits == 0) {3841Emit(SF(rn) | FPType(vd) | UCVTF | Rn(rn) | Rd(vd));3842} else {3843Emit(SF(rn) | FPType(vd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |3844Rd(vd));3845}3846}384738483849void Assembler::NEON3Same(const VRegister& vd,3850const VRegister& vn,3851const VRegister& vm,3852NEON3SameOp vop) {3853VIXL_ASSERT(AreSameFormat(vd, vn, vm));3854VIXL_ASSERT(vd.IsVector() || !vd.IsQ());38553856Instr format, op = vop;3857if (vd.IsScalar()) {3858op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);3859format = SFormat(vd);3860} else {3861format = VFormat(vd);3862}38633864Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));3865}386638673868void Assembler::NEONFP3Same(const VRegister& vd,3869const VRegister& vn,3870const VRegister& vm,3871Instr op) {3872VIXL_ASSERT(AreSameFormat(vd, vn, vm));3873Emit(FPFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));3874}387538763877void Assembler::NEON3SameFP16(const VRegister& vd,3878const VRegister& vn,3879const VRegister& vm,3880Instr op) {3881VIXL_ASSERT(AreSameFormat(vd, vn, vm));3882VIXL_ASSERT(vd.GetLaneSizeInBytes() == kHRegSizeInBytes);3883if (vd.Is8H()) op |= NEON_Q;3884Emit(op | Rm(vm) | Rn(vn) | Rd(vd));3885}388638873888// clang-format off3889#define NEON_FP2REGMISC_LIST(V) \3890V(fabs, NEON_FABS, FABS, FABS_h) \3891V(fneg, NEON_FNEG, FNEG, FNEG_h) \3892V(fsqrt, NEON_FSQRT, FSQRT, FSQRT_h) \3893V(frintn, NEON_FRINTN, FRINTN, FRINTN_h) \3894V(frinta, NEON_FRINTA, FRINTA, FRINTA_h) \3895V(frintp, NEON_FRINTP, FRINTP, FRINTP_h) \3896V(frintm, NEON_FRINTM, FRINTM, FRINTM_h) \3897V(frintx, NEON_FRINTX, FRINTX, FRINTX_h) \3898V(frintz, NEON_FRINTZ, FRINTZ, FRINTZ_h) \3899V(frinti, NEON_FRINTI, FRINTI, FRINTI_h) \3900V(frsqrte, NEON_FRSQRTE, NEON_FRSQRTE_scalar, NEON_FRSQRTE_H_scalar) \3901V(frecpe, NEON_FRECPE, NEON_FRECPE_scalar, NEON_FRECPE_H_scalar)3902// clang-format on39033904#define VIXL_DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP, SCA_OP_H) \3905void Assembler::FN(const VRegister& vd, const VRegister& vn) { \3906VIXL_ASSERT(CPUHas(CPUFeatures::kFP)); \3907Instr op; \3908if (vd.IsScalar()) { \3909if (vd.Is1H()) { \3910if ((static_cast<uint32_t>(SCA_OP_H) & \3911static_cast<uint32_t>(NEONScalar2RegMiscFP16FMask)) == \3912static_cast<uint32_t>(NEONScalar2RegMiscFP16Fixed)) { \3913VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf)); \3914} else { \3915VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf)); \3916} \3917op = SCA_OP_H; \3918} else { \3919if ((static_cast<uint32_t>(SCA_OP) & \3920static_cast<uint32_t>(NEONScalar2RegMiscFMask)) == \3921static_cast<uint32_t>(NEONScalar2RegMiscFixed)) { \3922VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \3923} \3924VIXL_ASSERT(vd.Is1S() || vd.Is1D()); \3925op = SCA_OP; \3926} \3927} else { \3928VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \3929VIXL_ASSERT(vd.Is4H() || vd.Is8H() || vd.Is2S() || vd.Is2D() || \3930vd.Is4S()); \3931if (vd.IsLaneSizeH()) { \3932VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \3933op = VEC_OP##_H; \3934if (vd.Is8H()) { \3935op |= static_cast<Instr>(NEON_Q); \3936} \3937} else { \3938op = VEC_OP; \3939} \3940} \3941if (vd.IsLaneSizeH()) { \3942NEONFP2RegMiscFP16(vd, vn, op); \3943} else { \3944NEONFP2RegMisc(vd, vn, op); \3945} \3946}3947NEON_FP2REGMISC_LIST(VIXL_DEFINE_ASM_FUNC)3948#undef VIXL_DEFINE_ASM_FUNC39493950// clang-format off3951#define NEON_FP2REGMISC_V85_LIST(V) \3952V(frint32x, NEON_FRINT32X, FRINT32X) \3953V(frint32z, NEON_FRINT32Z, FRINT32Z) \3954V(frint64x, NEON_FRINT64X, FRINT64X) \3955V(frint64z, NEON_FRINT64Z, FRINT64Z)3956// clang-format on39573958#define VIXL_DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \3959void Assembler::FN(const VRegister& vd, const VRegister& vn) { \3960VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt)); \3961Instr op; \3962if (vd.IsScalar()) { \3963VIXL_ASSERT(vd.Is1S() || vd.Is1D()); \3964op = SCA_OP; \3965} else { \3966VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \3967VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S()); \3968op = VEC_OP; \3969} \3970NEONFP2RegMisc(vd, vn, op); \3971}3972NEON_FP2REGMISC_V85_LIST(VIXL_DEFINE_ASM_FUNC)3973#undef VIXL_DEFINE_ASM_FUNC39743975void Assembler::NEONFP2RegMiscFP16(const VRegister& vd,3976const VRegister& vn,3977Instr op) {3978VIXL_ASSERT(AreSameFormat(vd, vn));3979Emit(op | Rn(vn) | Rd(vd));3980}398139823983void Assembler::NEONFP2RegMisc(const VRegister& vd,3984const VRegister& vn,3985Instr op) {3986VIXL_ASSERT(AreSameFormat(vd, vn));3987Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));3988}398939903991void Assembler::NEON2RegMisc(const VRegister& vd,3992const VRegister& vn,3993NEON2RegMiscOp vop,3994int value) {3995VIXL_ASSERT(AreSameFormat(vd, vn));3996VIXL_ASSERT(value == 0);3997USE(value);39983999Instr format, op = vop;4000if (vd.IsScalar()) {4001op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4002format = SFormat(vd);4003} else {4004format = VFormat(vd);4005}40064007Emit(format | op | Rn(vn) | Rd(vd));4008}400940104011void Assembler::cmeq(const VRegister& vd, const VRegister& vn, int value) {4012VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4013VIXL_ASSERT(vd.IsVector() || vd.Is1D());4014NEON2RegMisc(vd, vn, NEON_CMEQ_zero, value);4015}401640174018void Assembler::cmge(const VRegister& vd, const VRegister& vn, int value) {4019VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4020VIXL_ASSERT(vd.IsVector() || vd.Is1D());4021NEON2RegMisc(vd, vn, NEON_CMGE_zero, value);4022}402340244025void Assembler::cmgt(const VRegister& vd, const VRegister& vn, int value) {4026VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4027VIXL_ASSERT(vd.IsVector() || vd.Is1D());4028NEON2RegMisc(vd, vn, NEON_CMGT_zero, value);4029}403040314032void Assembler::cmle(const VRegister& vd, const VRegister& vn, int value) {4033VIXL_ASSERT(vd.IsVector() || vd.Is1D());4034VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4035NEON2RegMisc(vd, vn, NEON_CMLE_zero, value);4036}403740384039void Assembler::cmlt(const VRegister& vd, const VRegister& vn, int value) {4040VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4041VIXL_ASSERT(vd.IsVector() || vd.Is1D());4042NEON2RegMisc(vd, vn, NEON_CMLT_zero, value);4043}404440454046void Assembler::shll(const VRegister& vd, const VRegister& vn, int shift) {4047USE(shift);4048VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4049VIXL_ASSERT((vd.Is8H() && vn.Is8B() && shift == 8) ||4050(vd.Is4S() && vn.Is4H() && shift == 16) ||4051(vd.Is2D() && vn.Is2S() && shift == 32));4052Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));4053}405440554056void Assembler::shll2(const VRegister& vd, const VRegister& vn, int shift) {4057USE(shift);4058VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4059VIXL_ASSERT((vd.Is8H() && vn.Is16B() && shift == 8) ||4060(vd.Is4S() && vn.Is8H() && shift == 16) ||4061(vd.Is2D() && vn.Is4S() && shift == 32));4062Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd));4063}406440654066void Assembler::NEONFP2RegMisc(const VRegister& vd,4067const VRegister& vn,4068NEON2RegMiscOp vop,4069double value) {4070VIXL_ASSERT(AreSameFormat(vd, vn));4071VIXL_ASSERT(value == 0.0);4072USE(value);40734074Instr op = vop;4075if (vd.IsScalar()) {4076VIXL_ASSERT(vd.Is1S() || vd.Is1D());4077op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4078} else {4079VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S());4080}40814082Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));4083}408440854086void Assembler::NEONFP2RegMiscFP16(const VRegister& vd,4087const VRegister& vn,4088NEON2RegMiscFP16Op vop,4089double value) {4090VIXL_ASSERT(AreSameFormat(vd, vn));4091VIXL_ASSERT(value == 0.0);4092USE(value);40934094Instr op = vop;4095if (vd.IsScalar()) {4096VIXL_ASSERT(vd.Is1H());4097op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4098} else {4099VIXL_ASSERT(vd.Is4H() || vd.Is8H());4100if (vd.Is8H()) {4101op |= static_cast<Instr>(NEON_Q);4102}4103}41044105Emit(op | Rn(vn) | Rd(vd));4106}410741084109void Assembler::fcmeq(const VRegister& vd, const VRegister& vn, double value) {4110VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4111if (vd.IsLaneSizeH()) {4112VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4113NEONFP2RegMiscFP16(vd, vn, NEON_FCMEQ_H_zero, value);4114} else {4115NEONFP2RegMisc(vd, vn, NEON_FCMEQ_zero, value);4116}4117}411841194120void Assembler::fcmge(const VRegister& vd, const VRegister& vn, double value) {4121VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4122if (vd.IsLaneSizeH()) {4123VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4124NEONFP2RegMiscFP16(vd, vn, NEON_FCMGE_H_zero, value);4125} else {4126NEONFP2RegMisc(vd, vn, NEON_FCMGE_zero, value);4127}4128}412941304131void Assembler::fcmgt(const VRegister& vd, const VRegister& vn, double value) {4132VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4133if (vd.IsLaneSizeH()) {4134VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4135NEONFP2RegMiscFP16(vd, vn, NEON_FCMGT_H_zero, value);4136} else {4137NEONFP2RegMisc(vd, vn, NEON_FCMGT_zero, value);4138}4139}414041414142void Assembler::fcmle(const VRegister& vd, const VRegister& vn, double value) {4143VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4144if (vd.IsLaneSizeH()) {4145VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4146NEONFP2RegMiscFP16(vd, vn, NEON_FCMLE_H_zero, value);4147} else {4148NEONFP2RegMisc(vd, vn, NEON_FCMLE_zero, value);4149}4150}415141524153void Assembler::fcmlt(const VRegister& vd, const VRegister& vn, double value) {4154VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4155if (vd.IsLaneSizeH()) {4156VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4157NEONFP2RegMiscFP16(vd, vn, NEON_FCMLT_H_zero, value);4158} else {4159NEONFP2RegMisc(vd, vn, NEON_FCMLT_zero, value);4160}4161}416241634164void Assembler::frecpx(const VRegister& vd, const VRegister& vn) {4165VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4166VIXL_ASSERT(vd.IsScalar());4167VIXL_ASSERT(AreSameFormat(vd, vn));4168Instr op;4169if (vd.Is1H()) {4170VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4171op = NEON_FRECPX_H_scalar;4172} else {4173VIXL_ASSERT(vd.Is1S() || vd.Is1D());4174op = NEON_FRECPX_scalar;4175}4176Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd));4177}417841794180// clang-format off4181#define NEON_3SAME_LIST(V) \4182V(add, NEON_ADD, vd.IsVector() || vd.Is1D()) \4183V(addp, NEON_ADDP, vd.IsVector() || vd.Is1D()) \4184V(sub, NEON_SUB, vd.IsVector() || vd.Is1D()) \4185V(cmeq, NEON_CMEQ, vd.IsVector() || vd.Is1D()) \4186V(cmge, NEON_CMGE, vd.IsVector() || vd.Is1D()) \4187V(cmgt, NEON_CMGT, vd.IsVector() || vd.Is1D()) \4188V(cmhi, NEON_CMHI, vd.IsVector() || vd.Is1D()) \4189V(cmhs, NEON_CMHS, vd.IsVector() || vd.Is1D()) \4190V(cmtst, NEON_CMTST, vd.IsVector() || vd.Is1D()) \4191V(sshl, NEON_SSHL, vd.IsVector() || vd.Is1D()) \4192V(ushl, NEON_USHL, vd.IsVector() || vd.Is1D()) \4193V(srshl, NEON_SRSHL, vd.IsVector() || vd.Is1D()) \4194V(urshl, NEON_URSHL, vd.IsVector() || vd.Is1D()) \4195V(sqdmulh, NEON_SQDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \4196V(sqrdmulh, NEON_SQRDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \4197V(shadd, NEON_SHADD, vd.IsVector() && !vd.IsLaneSizeD()) \4198V(uhadd, NEON_UHADD, vd.IsVector() && !vd.IsLaneSizeD()) \4199V(srhadd, NEON_SRHADD, vd.IsVector() && !vd.IsLaneSizeD()) \4200V(urhadd, NEON_URHADD, vd.IsVector() && !vd.IsLaneSizeD()) \4201V(shsub, NEON_SHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \4202V(uhsub, NEON_UHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \4203V(smax, NEON_SMAX, vd.IsVector() && !vd.IsLaneSizeD()) \4204V(smaxp, NEON_SMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \4205V(smin, NEON_SMIN, vd.IsVector() && !vd.IsLaneSizeD()) \4206V(sminp, NEON_SMINP, vd.IsVector() && !vd.IsLaneSizeD()) \4207V(umax, NEON_UMAX, vd.IsVector() && !vd.IsLaneSizeD()) \4208V(umaxp, NEON_UMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \4209V(umin, NEON_UMIN, vd.IsVector() && !vd.IsLaneSizeD()) \4210V(uminp, NEON_UMINP, vd.IsVector() && !vd.IsLaneSizeD()) \4211V(saba, NEON_SABA, vd.IsVector() && !vd.IsLaneSizeD()) \4212V(sabd, NEON_SABD, vd.IsVector() && !vd.IsLaneSizeD()) \4213V(uaba, NEON_UABA, vd.IsVector() && !vd.IsLaneSizeD()) \4214V(uabd, NEON_UABD, vd.IsVector() && !vd.IsLaneSizeD()) \4215V(mla, NEON_MLA, vd.IsVector() && !vd.IsLaneSizeD()) \4216V(mls, NEON_MLS, vd.IsVector() && !vd.IsLaneSizeD()) \4217V(mul, NEON_MUL, vd.IsVector() && !vd.IsLaneSizeD()) \4218V(and_, NEON_AND, vd.Is8B() || vd.Is16B()) \4219V(orr, NEON_ORR, vd.Is8B() || vd.Is16B()) \4220V(orn, NEON_ORN, vd.Is8B() || vd.Is16B()) \4221V(eor, NEON_EOR, vd.Is8B() || vd.Is16B()) \4222V(bic, NEON_BIC, vd.Is8B() || vd.Is16B()) \4223V(bit, NEON_BIT, vd.Is8B() || vd.Is16B()) \4224V(bif, NEON_BIF, vd.Is8B() || vd.Is16B()) \4225V(bsl, NEON_BSL, vd.Is8B() || vd.Is16B()) \4226V(pmul, NEON_PMUL, vd.Is8B() || vd.Is16B()) \4227V(uqadd, NEON_UQADD, true) \4228V(sqadd, NEON_SQADD, true) \4229V(uqsub, NEON_UQSUB, true) \4230V(sqsub, NEON_SQSUB, true) \4231V(sqshl, NEON_SQSHL, true) \4232V(uqshl, NEON_UQSHL, true) \4233V(sqrshl, NEON_SQRSHL, true) \4234V(uqrshl, NEON_UQRSHL, true)4235// clang-format on42364237#define VIXL_DEFINE_ASM_FUNC(FN, OP, AS) \4238void Assembler::FN(const VRegister& vd, \4239const VRegister& vn, \4240const VRegister& vm) { \4241VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \4242VIXL_ASSERT(AS); \4243NEON3Same(vd, vn, vm, OP); \4244}4245NEON_3SAME_LIST(VIXL_DEFINE_ASM_FUNC)4246#undef VIXL_DEFINE_ASM_FUNC42474248// clang-format off4249#define NEON_FP3SAME_OP_LIST(V) \4250V(fmulx, NEON_FMULX, NEON_FMULX_scalar, NEON_FMULX_H_scalar) \4251V(frecps, NEON_FRECPS, NEON_FRECPS_scalar, NEON_FRECPS_H_scalar) \4252V(frsqrts, NEON_FRSQRTS, NEON_FRSQRTS_scalar, NEON_FRSQRTS_H_scalar) \4253V(fabd, NEON_FABD, NEON_FABD_scalar, NEON_FABD_H_scalar) \4254V(fmla, NEON_FMLA, 0, 0) \4255V(fmls, NEON_FMLS, 0, 0) \4256V(facge, NEON_FACGE, NEON_FACGE_scalar, NEON_FACGE_H_scalar) \4257V(facgt, NEON_FACGT, NEON_FACGT_scalar, NEON_FACGT_H_scalar) \4258V(fcmeq, NEON_FCMEQ, NEON_FCMEQ_scalar, NEON_FCMEQ_H_scalar) \4259V(fcmge, NEON_FCMGE, NEON_FCMGE_scalar, NEON_FCMGE_H_scalar) \4260V(fcmgt, NEON_FCMGT, NEON_FCMGT_scalar, NEON_FCMGT_H_scalar) \4261V(faddp, NEON_FADDP, 0, 0) \4262V(fmaxp, NEON_FMAXP, 0, 0) \4263V(fminp, NEON_FMINP, 0, 0) \4264V(fmaxnmp, NEON_FMAXNMP, 0, 0) \4265V(fadd, NEON_FADD, FADD, 0) \4266V(fsub, NEON_FSUB, FSUB, 0) \4267V(fmul, NEON_FMUL, FMUL, 0) \4268V(fdiv, NEON_FDIV, FDIV, 0) \4269V(fmax, NEON_FMAX, FMAX, 0) \4270V(fmin, NEON_FMIN, FMIN, 0) \4271V(fmaxnm, NEON_FMAXNM, FMAXNM, 0) \4272V(fminnm, NEON_FMINNM, FMINNM, 0) \4273V(fminnmp, NEON_FMINNMP, 0, 0)4274// clang-format on42754276// TODO: This macro is complicated because it classifies the instructions in the4277// macro list above, and treats each case differently. It could be somewhat4278// simpler if we were to split the macro, at the cost of some duplication.4279#define VIXL_DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP, SCA_OP_H) \4280void Assembler::FN(const VRegister& vd, \4281const VRegister& vn, \4282const VRegister& vm) { \4283VIXL_ASSERT(CPUHas(CPUFeatures::kFP)); \4284Instr op; \4285bool is_fp16 = false; \4286if ((SCA_OP != 0) && vd.IsScalar()) { \4287if ((SCA_OP_H != 0) && vd.Is1H()) { \4288VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf)); \4289is_fp16 = true; \4290op = SCA_OP_H; \4291} else { \4292VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D()); \4293if ((static_cast<uint32_t>(SCA_OP) & \4294static_cast<uint32_t>(NEONScalar3SameFMask)) == \4295static_cast<uint32_t>(NEONScalar3SameFixed)) { \4296VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \4297if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \4298} else if (vd.Is1H()) { \4299VIXL_ASSERT(CPUHas(CPUFeatures::kFPHalf)); \4300} \4301op = SCA_OP; \4302} \4303} else { \4304VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \4305VIXL_ASSERT(vd.IsVector()); \4306if (vd.Is4H() || vd.Is8H()) { \4307VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \4308is_fp16 = true; \4309op = VEC_OP##_H; \4310} else { \4311VIXL_ASSERT(vd.Is2S() || vd.Is2D() || vd.Is4S()); \4312op = VEC_OP; \4313} \4314} \4315if (is_fp16) { \4316NEON3SameFP16(vd, vn, vm, op); \4317} else { \4318NEONFP3Same(vd, vn, vm, op); \4319} \4320}4321NEON_FP3SAME_OP_LIST(VIXL_DEFINE_ASM_FUNC)4322#undef VIXL_DEFINE_ASM_FUNC432343244325// clang-format off4326#define NEON_FHM_LIST(V) \4327V(fmlal, NEON_FMLAL) \4328V(fmlal2, NEON_FMLAL2) \4329V(fmlsl, NEON_FMLSL) \4330V(fmlsl2, NEON_FMLSL2)4331// clang-format on43324333#define VIXL_DEFINE_ASM_FUNC(FN, VEC_OP) \4334void Assembler::FN(const VRegister& vd, \4335const VRegister& vn, \4336const VRegister& vm) { \4337VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, \4338CPUFeatures::kFP, \4339CPUFeatures::kNEONHalf, \4340CPUFeatures::kFHM)); \4341VIXL_ASSERT((vd.Is2S() && vn.Is2H() && vm.Is2H()) || \4342(vd.Is4S() && vn.Is4H() && vm.Is4H())); \4343Emit(FPFormat(vd) | VEC_OP | Rm(vm) | Rn(vn) | Rd(vd)); \4344}4345NEON_FHM_LIST(VIXL_DEFINE_ASM_FUNC)4346#undef VIXL_DEFINE_ASM_FUNC434743484349void Assembler::addp(const VRegister& vd, const VRegister& vn) {4350VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4351VIXL_ASSERT((vd.Is1D() && vn.Is2D()));4352Emit(SFormat(vd) | NEON_ADDP_scalar | Rn(vn) | Rd(vd));4353}435443554356void Assembler::sqrdmlah(const VRegister& vd,4357const VRegister& vn,4358const VRegister& vm) {4359VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM));4360VIXL_ASSERT(AreSameFormat(vd, vn, vm));4361VIXL_ASSERT(vd.IsVector() || !vd.IsQ());43624363Instr format, op = NEON_SQRDMLAH;4364if (vd.IsScalar()) {4365op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4366format = SFormat(vd);4367} else {4368format = VFormat(vd);4369}43704371Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));4372}437343744375void Assembler::sqrdmlsh(const VRegister& vd,4376const VRegister& vn,4377const VRegister& vm) {4378VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM));4379VIXL_ASSERT(AreSameFormat(vd, vn, vm));4380VIXL_ASSERT(vd.IsVector() || !vd.IsQ());43814382Instr format, op = NEON_SQRDMLSH;4383if (vd.IsScalar()) {4384op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4385format = SFormat(vd);4386} else {4387format = VFormat(vd);4388}43894390Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd));4391}439243934394void Assembler::sdot(const VRegister& vd,4395const VRegister& vn,4396const VRegister& vm) {4397VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));4398VIXL_ASSERT(AreSameFormat(vn, vm));4399VIXL_ASSERT((vd.Is2S() && vn.Is8B()) || (vd.Is4S() && vn.Is16B()));44004401Emit(VFormat(vd) | NEON_SDOT | Rm(vm) | Rn(vn) | Rd(vd));4402}440344044405void Assembler::udot(const VRegister& vd,4406const VRegister& vn,4407const VRegister& vm) {4408VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));4409VIXL_ASSERT(AreSameFormat(vn, vm));4410VIXL_ASSERT((vd.Is2S() && vn.Is8B()) || (vd.Is4S() && vn.Is16B()));44114412Emit(VFormat(vd) | NEON_UDOT | Rm(vm) | Rn(vn) | Rd(vd));4413}44144415void Assembler::usdot(const VRegister& vd,4416const VRegister& vn,4417const VRegister& vm) {4418VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kI8MM));4419VIXL_ASSERT(AreSameFormat(vn, vm));4420VIXL_ASSERT((vd.Is2S() && vn.Is8B()) || (vd.Is4S() && vn.Is16B()));44214422Emit(VFormat(vd) | 0x0e809c00 | Rm(vm) | Rn(vn) | Rd(vd));4423}44244425void Assembler::faddp(const VRegister& vd, const VRegister& vn) {4426VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4427VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||4428(vd.Is1H() && vn.Is2H()));4429if (vd.Is1H()) {4430VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4431Emit(NEON_FADDP_h_scalar | Rn(vn) | Rd(vd));4432} else {4433Emit(FPFormat(vd) | NEON_FADDP_scalar | Rn(vn) | Rd(vd));4434}4435}443644374438void Assembler::fmaxp(const VRegister& vd, const VRegister& vn) {4439VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4440VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||4441(vd.Is1H() && vn.Is2H()));4442if (vd.Is1H()) {4443VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4444Emit(NEON_FMAXP_h_scalar | Rn(vn) | Rd(vd));4445} else {4446Emit(FPFormat(vd) | NEON_FMAXP_scalar | Rn(vn) | Rd(vd));4447}4448}444944504451void Assembler::fminp(const VRegister& vd, const VRegister& vn) {4452VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4453VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||4454(vd.Is1H() && vn.Is2H()));4455if (vd.Is1H()) {4456VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4457Emit(NEON_FMINP_h_scalar | Rn(vn) | Rd(vd));4458} else {4459Emit(FPFormat(vd) | NEON_FMINP_scalar | Rn(vn) | Rd(vd));4460}4461}446244634464void Assembler::fmaxnmp(const VRegister& vd, const VRegister& vn) {4465VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4466VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||4467(vd.Is1H() && vn.Is2H()));4468if (vd.Is1H()) {4469VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4470Emit(NEON_FMAXNMP_h_scalar | Rn(vn) | Rd(vd));4471} else {4472Emit(FPFormat(vd) | NEON_FMAXNMP_scalar | Rn(vn) | Rd(vd));4473}4474}447544764477void Assembler::fminnmp(const VRegister& vd, const VRegister& vn) {4478VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON));4479VIXL_ASSERT((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D()) ||4480(vd.Is1H() && vn.Is2H()));4481if (vd.Is1H()) {4482VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4483Emit(NEON_FMINNMP_h_scalar | Rn(vn) | Rd(vd));4484} else {4485Emit(FPFormat(vd) | NEON_FMINNMP_scalar | Rn(vn) | Rd(vd));4486}4487}448844894490// v8.3 complex numbers - floating-point complex multiply accumulate.4491void Assembler::fcmla(const VRegister& vd,4492const VRegister& vn,4493const VRegister& vm,4494int vm_index,4495int rot) {4496VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));4497VIXL_ASSERT(vd.IsVector() && AreSameFormat(vd, vn));4498VIXL_ASSERT((vm.IsH() && (vd.Is8H() || vd.Is4H())) ||4499(vm.IsS() && vd.Is4S()));4500if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4501int index_num_bits = vd.Is4S() ? 1 : 2;4502Emit(VFormat(vd) | Rm(vm) | NEON_FCMLA_byelement |4503ImmNEONHLM(vm_index, index_num_bits) | ImmRotFcmlaSca(rot) | Rn(vn) |4504Rd(vd));4505}450645074508void Assembler::fcmla(const VRegister& vd,4509const VRegister& vn,4510const VRegister& vm,4511int rot) {4512VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));4513VIXL_ASSERT(AreSameFormat(vd, vn, vm));4514VIXL_ASSERT(vd.IsVector() && !vd.IsLaneSizeB());4515if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4516Emit(VFormat(vd) | Rm(vm) | NEON_FCMLA | ImmRotFcmlaVec(rot) | Rn(vn) |4517Rd(vd));4518}451945204521// v8.3 complex numbers - floating-point complex add.4522void Assembler::fcadd(const VRegister& vd,4523const VRegister& vn,4524const VRegister& vm,4525int rot) {4526VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kFcma));4527VIXL_ASSERT(AreSameFormat(vd, vn, vm));4528VIXL_ASSERT(vd.IsVector() && !vd.IsLaneSizeB());4529if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));4530Emit(VFormat(vd) | Rm(vm) | NEON_FCADD | ImmRotFcadd(rot) | Rn(vn) | Rd(vd));4531}453245334534void Assembler::orr(const VRegister& vd, const int imm8, const int left_shift) {4535VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4536NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_ORR);4537}453845394540void Assembler::mov(const VRegister& vd, const VRegister& vn) {4541VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4542VIXL_ASSERT(AreSameFormat(vd, vn));4543if (vd.IsD()) {4544orr(vd.V8B(), vn.V8B(), vn.V8B());4545} else {4546VIXL_ASSERT(vd.IsQ());4547orr(vd.V16B(), vn.V16B(), vn.V16B());4548}4549}455045514552void Assembler::bic(const VRegister& vd, const int imm8, const int left_shift) {4553VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4554NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_BIC);4555}455645574558void Assembler::movi(const VRegister& vd,4559const uint64_t imm,4560Shift shift,4561const int shift_amount) {4562VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4563VIXL_ASSERT((shift == LSL) || (shift == MSL));4564if (vd.Is2D() || vd.Is1D()) {4565VIXL_ASSERT(shift_amount == 0);4566int imm8 = 0;4567for (int i = 0; i < 8; ++i) {4568int byte = (imm >> (i * 8)) & 0xff;4569VIXL_ASSERT((byte == 0) || (byte == 0xff));4570if (byte == 0xff) {4571imm8 |= (1 << i);4572}4573}4574int q = vd.Is2D() ? NEON_Q : 0;4575Emit(q | NEONModImmOp(1) | NEONModifiedImmediate_MOVI |4576ImmNEONabcdefgh(imm8) | NEONCmode(0xe) | Rd(vd));4577} else if (shift == LSL) {4578VIXL_ASSERT(IsUint8(imm));4579NEONModifiedImmShiftLsl(vd,4580static_cast<int>(imm),4581shift_amount,4582NEONModifiedImmediate_MOVI);4583} else {4584VIXL_ASSERT(IsUint8(imm));4585NEONModifiedImmShiftMsl(vd,4586static_cast<int>(imm),4587shift_amount,4588NEONModifiedImmediate_MOVI);4589}4590}459145924593void Assembler::mvn(const VRegister& vd, const VRegister& vn) {4594VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4595VIXL_ASSERT(AreSameFormat(vd, vn));4596if (vd.IsD()) {4597not_(vd.V8B(), vn.V8B());4598} else {4599VIXL_ASSERT(vd.IsQ());4600not_(vd.V16B(), vn.V16B());4601}4602}460346044605void Assembler::mvni(const VRegister& vd,4606const int imm8,4607Shift shift,4608const int shift_amount) {4609VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4610VIXL_ASSERT((shift == LSL) || (shift == MSL));4611if (shift == LSL) {4612NEONModifiedImmShiftLsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);4613} else {4614NEONModifiedImmShiftMsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI);4615}4616}461746184619void Assembler::NEONFPByElement(const VRegister& vd,4620const VRegister& vn,4621const VRegister& vm,4622int vm_index,4623NEONByIndexedElementOp vop,4624NEONByIndexedElementOp vop_half) {4625VIXL_ASSERT(AreSameFormat(vd, vn));4626VIXL_ASSERT((vd.Is2S() && vm.Is1S()) || (vd.Is4S() && vm.Is1S()) ||4627(vd.Is1S() && vm.Is1S()) || (vd.Is2D() && vm.Is1D()) ||4628(vd.Is1D() && vm.Is1D()) || (vd.Is4H() && vm.Is1H()) ||4629(vd.Is8H() && vm.Is1H()) || (vd.Is1H() && vm.Is1H()));4630VIXL_ASSERT((vm.Is1S() && (vm_index < 4)) || (vm.Is1D() && (vm_index < 2)) ||4631(vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)));46324633Instr op = vop;4634int index_num_bits;4635if (vm.Is1D()) {4636index_num_bits = 1;4637} else if (vm.Is1S()) {4638index_num_bits = 2;4639} else {4640index_num_bits = 3;4641op = vop_half;4642}46434644if (vd.IsScalar()) {4645op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4646}46474648if (!vm.Is1H()) {4649op |= FPFormat(vd);4650} else if (vd.Is8H()) {4651op |= static_cast<Instr>(NEON_Q);4652}46534654Emit(op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));4655}465646574658void Assembler::NEONByElement(const VRegister& vd,4659const VRegister& vn,4660const VRegister& vm,4661int vm_index,4662NEONByIndexedElementOp vop) {4663VIXL_ASSERT(AreSameFormat(vd, vn));4664VIXL_ASSERT((vd.Is4H() && vm.Is1H()) || (vd.Is8H() && vm.Is1H()) ||4665(vd.Is1H() && vm.Is1H()) || (vd.Is2S() && vm.Is1S()) ||4666(vd.Is4S() && vm.Is1S()) || (vd.Is1S() && vm.Is1S()));4667VIXL_ASSERT((vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)) ||4668(vm.Is1S() && (vm_index < 4)));46694670Instr format, op = vop;4671int index_num_bits = vm.Is1H() ? 3 : 2;4672if (vd.IsScalar()) {4673op |= static_cast<Instr>(NEONScalar) | static_cast<Instr>(NEON_Q);4674format = SFormat(vn);4675} else {4676format = VFormat(vn);4677}4678Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |4679Rd(vd));4680}468146824683void Assembler::NEONByElementL(const VRegister& vd,4684const VRegister& vn,4685const VRegister& vm,4686int vm_index,4687NEONByIndexedElementOp vop) {4688VIXL_ASSERT((vd.Is4S() && vn.Is4H() && vm.Is1H()) ||4689(vd.Is4S() && vn.Is8H() && vm.Is1H()) ||4690(vd.Is1S() && vn.Is1H() && vm.Is1H()) ||4691(vd.Is2D() && vn.Is2S() && vm.Is1S()) ||4692(vd.Is2D() && vn.Is4S() && vm.Is1S()) ||4693(vd.Is1D() && vn.Is1S() && vm.Is1S()));46944695VIXL_ASSERT((vm.Is1H() && (vm.GetCode() < 16) && (vm_index < 8)) ||4696(vm.Is1S() && (vm_index < 4)));46974698Instr format, op = vop;4699int index_num_bits = vm.Is1H() ? 3 : 2;4700if (vd.IsScalar()) {4701op |= static_cast<Instr>(NEONScalar) | static_cast<Instr>(NEON_Q);4702format = SFormat(vn);4703} else {4704format = VFormat(vn);4705}4706Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |4707Rd(vd));4708}470947104711void Assembler::sdot(const VRegister& vd,4712const VRegister& vn,4713const VRegister& vm,4714int vm_index) {4715VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));4716VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||4717(vd.Is4S() && vn.Is16B() && vm.Is1S4B()));47184719int index_num_bits = 2;4720Emit(VFormat(vd) | NEON_SDOT_byelement |4721ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));4722}472347244725void Assembler::udot(const VRegister& vd,4726const VRegister& vn,4727const VRegister& vm,4728int vm_index) {4729VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kDotProduct));4730VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||4731(vd.Is4S() && vn.Is16B() && vm.Is1S4B()));47324733int index_num_bits = 2;4734Emit(VFormat(vd) | NEON_UDOT_byelement |4735ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | Rd(vd));4736}47374738void Assembler::sudot(const VRegister& vd,4739const VRegister& vn,4740const VRegister& vm,4741int vm_index) {4742VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kI8MM));4743VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||4744(vd.Is4S() && vn.Is16B() && vm.Is1S4B()));4745int q = vd.Is4S() ? (1U << NEONQ_offset) : 0;4746int index_num_bits = 2;4747Emit(q | 0x0f00f000 | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |4748Rd(vd));4749}475047514752void Assembler::usdot(const VRegister& vd,4753const VRegister& vn,4754const VRegister& vm,4755int vm_index) {4756VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kI8MM));4757VIXL_ASSERT((vd.Is2S() && vn.Is8B() && vm.Is1S4B()) ||4758(vd.Is4S() && vn.Is16B() && vm.Is1S4B()));4759int q = vd.Is4S() ? (1U << NEONQ_offset) : 0;4760int index_num_bits = 2;4761Emit(q | 0x0f80f000 | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) |4762Rd(vd));4763}47644765// clang-format off4766#define NEON_BYELEMENT_LIST(V) \4767V(mul, NEON_MUL_byelement, vn.IsVector()) \4768V(mla, NEON_MLA_byelement, vn.IsVector()) \4769V(mls, NEON_MLS_byelement, vn.IsVector()) \4770V(sqdmulh, NEON_SQDMULH_byelement, true) \4771V(sqrdmulh, NEON_SQRDMULH_byelement, true) \4772// clang-format on47734774#define VIXL_DEFINE_ASM_FUNC(FN, OP, AS) \4775void Assembler::FN(const VRegister& vd, \4776const VRegister& vn, \4777const VRegister& vm, \4778int vm_index) { \4779VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \4780VIXL_ASSERT(AS); \4781NEONByElement(vd, vn, vm, vm_index, OP); \4782}4783NEON_BYELEMENT_LIST(VIXL_DEFINE_ASM_FUNC)4784#undef VIXL_DEFINE_ASM_FUNC478547864787// clang-format off4788#define NEON_BYELEMENT_RDM_LIST(V) \4789V(sqrdmlah, NEON_SQRDMLAH_byelement) \4790V(sqrdmlsh, NEON_SQRDMLSH_byelement)4791// clang-format on47924793#define VIXL_DEFINE_ASM_FUNC(FN, OP) \4794void Assembler::FN(const VRegister& vd, \4795const VRegister& vn, \4796const VRegister& vm, \4797int vm_index) { \4798VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kRDM)); \4799NEONByElement(vd, vn, vm, vm_index, OP); \4800}4801NEON_BYELEMENT_RDM_LIST(VIXL_DEFINE_ASM_FUNC)4802#undef VIXL_DEFINE_ASM_FUNC480348044805// clang-format off4806#define NEON_FPBYELEMENT_LIST(V) \4807V(fmul, NEON_FMUL_byelement, NEON_FMUL_H_byelement) \4808V(fmla, NEON_FMLA_byelement, NEON_FMLA_H_byelement) \4809V(fmls, NEON_FMLS_byelement, NEON_FMLS_H_byelement) \4810V(fmulx, NEON_FMULX_byelement, NEON_FMULX_H_byelement)4811// clang-format on48124813#define VIXL_DEFINE_ASM_FUNC(FN, OP, OP_H) \4814void Assembler::FN(const VRegister& vd, \4815const VRegister& vn, \4816const VRegister& vm, \4817int vm_index) { \4818VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON)); \4819if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \4820NEONFPByElement(vd, vn, vm, vm_index, OP, OP_H); \4821}4822NEON_FPBYELEMENT_LIST(VIXL_DEFINE_ASM_FUNC)4823#undef VIXL_DEFINE_ASM_FUNC482448254826// clang-format off4827#define NEON_BYELEMENT_LONG_LIST(V) \4828V(sqdmull, NEON_SQDMULL_byelement, vn.IsScalar() || vn.IsD()) \4829V(sqdmull2, NEON_SQDMULL_byelement, vn.IsVector() && vn.IsQ()) \4830V(sqdmlal, NEON_SQDMLAL_byelement, vn.IsScalar() || vn.IsD()) \4831V(sqdmlal2, NEON_SQDMLAL_byelement, vn.IsVector() && vn.IsQ()) \4832V(sqdmlsl, NEON_SQDMLSL_byelement, vn.IsScalar() || vn.IsD()) \4833V(sqdmlsl2, NEON_SQDMLSL_byelement, vn.IsVector() && vn.IsQ()) \4834V(smull, NEON_SMULL_byelement, vn.IsVector() && vn.IsD()) \4835V(smull2, NEON_SMULL_byelement, vn.IsVector() && vn.IsQ()) \4836V(umull, NEON_UMULL_byelement, vn.IsVector() && vn.IsD()) \4837V(umull2, NEON_UMULL_byelement, vn.IsVector() && vn.IsQ()) \4838V(smlal, NEON_SMLAL_byelement, vn.IsVector() && vn.IsD()) \4839V(smlal2, NEON_SMLAL_byelement, vn.IsVector() && vn.IsQ()) \4840V(umlal, NEON_UMLAL_byelement, vn.IsVector() && vn.IsD()) \4841V(umlal2, NEON_UMLAL_byelement, vn.IsVector() && vn.IsQ()) \4842V(smlsl, NEON_SMLSL_byelement, vn.IsVector() && vn.IsD()) \4843V(smlsl2, NEON_SMLSL_byelement, vn.IsVector() && vn.IsQ()) \4844V(umlsl, NEON_UMLSL_byelement, vn.IsVector() && vn.IsD()) \4845V(umlsl2, NEON_UMLSL_byelement, vn.IsVector() && vn.IsQ())4846// clang-format on484748484849#define VIXL_DEFINE_ASM_FUNC(FN, OP, AS) \4850void Assembler::FN(const VRegister& vd, \4851const VRegister& vn, \4852const VRegister& vm, \4853int vm_index) { \4854VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \4855VIXL_ASSERT(AS); \4856NEONByElementL(vd, vn, vm, vm_index, OP); \4857}4858NEON_BYELEMENT_LONG_LIST(VIXL_DEFINE_ASM_FUNC)4859#undef VIXL_DEFINE_ASM_FUNC486048614862// clang-format off4863#define NEON_BYELEMENT_FHM_LIST(V) \4864V(fmlal, NEON_FMLAL_H_byelement) \4865V(fmlal2, NEON_FMLAL2_H_byelement) \4866V(fmlsl, NEON_FMLSL_H_byelement) \4867V(fmlsl2, NEON_FMLSL2_H_byelement)4868// clang-format on486948704871#define VIXL_DEFINE_ASM_FUNC(FN, OP) \4872void Assembler::FN(const VRegister& vd, \4873const VRegister& vn, \4874const VRegister& vm, \4875int vm_index) { \4876VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, \4877CPUFeatures::kFP, \4878CPUFeatures::kNEONHalf, \4879CPUFeatures::kFHM)); \4880VIXL_ASSERT((vd.Is2S() && vn.Is2H()) || (vd.Is4S() && vn.Is4H())); \4881VIXL_ASSERT(vm.IsH()); \4882VIXL_ASSERT((vm_index >= 0) && (vm_index < 8)); \4883/* Vm itself can only be in the bottom 16 registers. */ \4884VIXL_ASSERT(vm.GetCode() < 16); \4885Emit(FPFormat(vd) | OP | Rd(vd) | Rn(vn) | Rm(vm) | \4886ImmNEONHLM(vm_index, 3)); \4887}4888NEON_BYELEMENT_FHM_LIST(VIXL_DEFINE_ASM_FUNC)4889#undef VIXL_DEFINE_ASM_FUNC48904891void Assembler::suqadd(const VRegister& vd, const VRegister& vn) {4892VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4893NEON2RegMisc(vd, vn, NEON_SUQADD);4894}489548964897void Assembler::usqadd(const VRegister& vd, const VRegister& vn) {4898VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4899NEON2RegMisc(vd, vn, NEON_USQADD);4900}490149024903void Assembler::abs(const VRegister& vd, const VRegister& vn) {4904VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4905VIXL_ASSERT(vd.IsVector() || vd.Is1D());4906NEON2RegMisc(vd, vn, NEON_ABS);4907}490849094910void Assembler::sqabs(const VRegister& vd, const VRegister& vn) {4911VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4912NEON2RegMisc(vd, vn, NEON_SQABS);4913}491449154916void Assembler::neg(const VRegister& vd, const VRegister& vn) {4917VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4918VIXL_ASSERT(vd.IsVector() || vd.Is1D());4919NEON2RegMisc(vd, vn, NEON_NEG);4920}492149224923void Assembler::sqneg(const VRegister& vd, const VRegister& vn) {4924VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4925NEON2RegMisc(vd, vn, NEON_SQNEG);4926}492749284929void Assembler::NEONXtn(const VRegister& vd,4930const VRegister& vn,4931NEON2RegMiscOp vop) {4932VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4933Instr format, op = vop;4934if (vd.IsScalar()) {4935VIXL_ASSERT((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||4936(vd.Is1S() && vn.Is1D()));4937op |= static_cast<Instr>(NEON_Q) | static_cast<Instr>(NEONScalar);4938format = SFormat(vd);4939} else {4940VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||4941(vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||4942(vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));4943format = VFormat(vd);4944}4945Emit(format | op | Rn(vn) | Rd(vd));4946}494749484949void Assembler::xtn(const VRegister& vd, const VRegister& vn) {4950VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4951VIXL_ASSERT(vd.IsVector() && vd.IsD());4952NEONXtn(vd, vn, NEON_XTN);4953}495449554956void Assembler::xtn2(const VRegister& vd, const VRegister& vn) {4957VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4958VIXL_ASSERT(vd.IsVector() && vd.IsQ());4959NEONXtn(vd, vn, NEON_XTN);4960}496149624963void Assembler::sqxtn(const VRegister& vd, const VRegister& vn) {4964VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4965VIXL_ASSERT(vd.IsScalar() || vd.IsD());4966NEONXtn(vd, vn, NEON_SQXTN);4967}496849694970void Assembler::sqxtn2(const VRegister& vd, const VRegister& vn) {4971VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4972VIXL_ASSERT(vd.IsVector() && vd.IsQ());4973NEONXtn(vd, vn, NEON_SQXTN);4974}497549764977void Assembler::sqxtun(const VRegister& vd, const VRegister& vn) {4978VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4979VIXL_ASSERT(vd.IsScalar() || vd.IsD());4980NEONXtn(vd, vn, NEON_SQXTUN);4981}498249834984void Assembler::sqxtun2(const VRegister& vd, const VRegister& vn) {4985VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4986VIXL_ASSERT(vd.IsVector() && vd.IsQ());4987NEONXtn(vd, vn, NEON_SQXTUN);4988}498949904991void Assembler::uqxtn(const VRegister& vd, const VRegister& vn) {4992VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));4993VIXL_ASSERT(vd.IsScalar() || vd.IsD());4994NEONXtn(vd, vn, NEON_UQXTN);4995}499649974998void Assembler::uqxtn2(const VRegister& vd, const VRegister& vn) {4999VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5000VIXL_ASSERT(vd.IsVector() && vd.IsQ());5001NEONXtn(vd, vn, NEON_UQXTN);5002}500350045005// NEON NOT and RBIT are distinguised by bit 22, the bottom bit of "size".5006void Assembler::not_(const VRegister& vd, const VRegister& vn) {5007VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5008VIXL_ASSERT(AreSameFormat(vd, vn));5009VIXL_ASSERT(vd.Is8B() || vd.Is16B());5010Emit(VFormat(vd) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));5011}501250135014void Assembler::rbit(const VRegister& vd, const VRegister& vn) {5015VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5016VIXL_ASSERT(AreSameFormat(vd, vn));5017VIXL_ASSERT(vd.Is8B() || vd.Is16B());5018Emit(VFormat(vn) | (1 << NEONSize_offset) | NEON_RBIT_NOT | Rn(vn) | Rd(vd));5019}502050215022void Assembler::ext(const VRegister& vd,5023const VRegister& vn,5024const VRegister& vm,5025int index) {5026VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5027VIXL_ASSERT(AreSameFormat(vd, vn, vm));5028VIXL_ASSERT(vd.Is8B() || vd.Is16B());5029VIXL_ASSERT((0 <= index) && (index < vd.GetLanes()));5030Emit(VFormat(vd) | NEON_EXT | Rm(vm) | ImmNEONExt(index) | Rn(vn) | Rd(vd));5031}503250335034void Assembler::dup(const VRegister& vd, const VRegister& vn, int vn_index) {5035VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5036Instr q, scalar;50375038// We support vn arguments of the form vn.VxT() or vn.T(), where x is the5039// number of lanes, and T is b, h, s or d.5040int lane_size = vn.GetLaneSizeInBytes();5041NEONFormatField format;5042switch (lane_size) {5043case 1:5044format = NEON_16B;5045break;5046case 2:5047format = NEON_8H;5048break;5049case 4:5050format = NEON_4S;5051break;5052default:5053VIXL_ASSERT(lane_size == 8);5054format = NEON_2D;5055break;5056}50575058if (vd.IsScalar()) {5059q = NEON_Q;5060scalar = NEONScalar;5061} else {5062VIXL_ASSERT(!vd.Is1D());5063q = vd.IsD() ? 0 : NEON_Q;5064scalar = 0;5065}5066Emit(q | scalar | NEON_DUP_ELEMENT | ImmNEON5(format, vn_index) | Rn(vn) |5067Rd(vd));5068}506950705071void Assembler::mov(const VRegister& vd, const VRegister& vn, int vn_index) {5072VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5073VIXL_ASSERT(vd.IsScalar());5074dup(vd, vn, vn_index);5075}507650775078void Assembler::dup(const VRegister& vd, const Register& rn) {5079VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5080VIXL_ASSERT(!vd.Is1D());5081VIXL_ASSERT(vd.Is2D() == rn.IsX());5082int q = vd.IsD() ? 0 : NEON_Q;5083Emit(q | NEON_DUP_GENERAL | ImmNEON5(VFormat(vd), 0) | Rn(rn) | Rd(vd));5084}508550865087void Assembler::ins(const VRegister& vd,5088int vd_index,5089const VRegister& vn,5090int vn_index) {5091VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5092VIXL_ASSERT(AreSameFormat(vd, vn));5093// We support vd arguments of the form vd.VxT() or vd.T(), where x is the5094// number of lanes, and T is b, h, s or d.5095int lane_size = vd.GetLaneSizeInBytes();5096NEONFormatField format;5097switch (lane_size) {5098case 1:5099format = NEON_16B;5100break;5101case 2:5102format = NEON_8H;5103break;5104case 4:5105format = NEON_4S;5106break;5107default:5108VIXL_ASSERT(lane_size == 8);5109format = NEON_2D;5110break;5111}51125113VIXL_ASSERT(5114(0 <= vd_index) &&5115(vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));5116VIXL_ASSERT(5117(0 <= vn_index) &&5118(vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));5119Emit(NEON_INS_ELEMENT | ImmNEON5(format, vd_index) |5120ImmNEON4(format, vn_index) | Rn(vn) | Rd(vd));5121}512251235124void Assembler::mov(const VRegister& vd,5125int vd_index,5126const VRegister& vn,5127int vn_index) {5128VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5129ins(vd, vd_index, vn, vn_index);5130}513151325133void Assembler::ins(const VRegister& vd, int vd_index, const Register& rn) {5134VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5135// We support vd arguments of the form vd.VxT() or vd.T(), where x is the5136// number of lanes, and T is b, h, s or d.5137int lane_size = vd.GetLaneSizeInBytes();5138NEONFormatField format;5139switch (lane_size) {5140case 1:5141format = NEON_16B;5142VIXL_ASSERT(rn.IsW());5143break;5144case 2:5145format = NEON_8H;5146VIXL_ASSERT(rn.IsW());5147break;5148case 4:5149format = NEON_4S;5150VIXL_ASSERT(rn.IsW());5151break;5152default:5153VIXL_ASSERT(lane_size == 8);5154VIXL_ASSERT(rn.IsX());5155format = NEON_2D;5156break;5157}51585159VIXL_ASSERT(5160(0 <= vd_index) &&5161(vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));5162Emit(NEON_INS_GENERAL | ImmNEON5(format, vd_index) | Rn(rn) | Rd(vd));5163}516451655166void Assembler::mov(const VRegister& vd, int vd_index, const Register& rn) {5167VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5168ins(vd, vd_index, rn);5169}517051715172void Assembler::umov(const Register& rd, const VRegister& vn, int vn_index) {5173VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5174// We support vn arguments of the form vn.VxT() or vn.T(), where x is the5175// number of lanes, and T is b, h, s or d.5176int lane_size = vn.GetLaneSizeInBytes();5177NEONFormatField format;5178Instr q = 0;5179switch (lane_size) {5180case 1:5181format = NEON_16B;5182VIXL_ASSERT(rd.IsW());5183break;5184case 2:5185format = NEON_8H;5186VIXL_ASSERT(rd.IsW());5187break;5188case 4:5189format = NEON_4S;5190VIXL_ASSERT(rd.IsW());5191break;5192default:5193VIXL_ASSERT(lane_size == 8);5194VIXL_ASSERT(rd.IsX());5195format = NEON_2D;5196q = NEON_Q;5197break;5198}51995200VIXL_ASSERT(5201(0 <= vn_index) &&5202(vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));5203Emit(q | NEON_UMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));5204}520552065207void Assembler::mov(const Register& rd, const VRegister& vn, int vn_index) {5208VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5209VIXL_ASSERT(vn.GetSizeInBytes() >= 4);5210umov(rd, vn, vn_index);5211}521252135214void Assembler::smov(const Register& rd, const VRegister& vn, int vn_index) {5215VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5216// We support vn arguments of the form vn.VxT() or vn.T(), where x is the5217// number of lanes, and T is b, h, s.5218int lane_size = vn.GetLaneSizeInBytes();5219NEONFormatField format;5220Instr q = 0;5221VIXL_ASSERT(lane_size != 8);5222switch (lane_size) {5223case 1:5224format = NEON_16B;5225break;5226case 2:5227format = NEON_8H;5228break;5229default:5230VIXL_ASSERT(lane_size == 4);5231VIXL_ASSERT(rd.IsX());5232format = NEON_4S;5233break;5234}5235q = rd.IsW() ? 0 : NEON_Q;5236VIXL_ASSERT(5237(0 <= vn_index) &&5238(vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format))));5239Emit(q | NEON_SMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd));5240}524152425243void Assembler::cls(const VRegister& vd, const VRegister& vn) {5244VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5245VIXL_ASSERT(AreSameFormat(vd, vn));5246VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());5247Emit(VFormat(vn) | NEON_CLS | Rn(vn) | Rd(vd));5248}524952505251void Assembler::clz(const VRegister& vd, const VRegister& vn) {5252VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5253VIXL_ASSERT(AreSameFormat(vd, vn));5254VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());5255Emit(VFormat(vn) | NEON_CLZ | Rn(vn) | Rd(vd));5256}525752585259void Assembler::cnt(const VRegister& vd, const VRegister& vn) {5260VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5261VIXL_ASSERT(AreSameFormat(vd, vn));5262VIXL_ASSERT(vd.Is8B() || vd.Is16B());5263Emit(VFormat(vn) | NEON_CNT | Rn(vn) | Rd(vd));5264}526552665267void Assembler::rev16(const VRegister& vd, const VRegister& vn) {5268VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5269VIXL_ASSERT(AreSameFormat(vd, vn));5270VIXL_ASSERT(vd.Is8B() || vd.Is16B());5271Emit(VFormat(vn) | NEON_REV16 | Rn(vn) | Rd(vd));5272}527352745275void Assembler::rev32(const VRegister& vd, const VRegister& vn) {5276VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5277VIXL_ASSERT(AreSameFormat(vd, vn));5278VIXL_ASSERT(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H());5279Emit(VFormat(vn) | NEON_REV32 | Rn(vn) | Rd(vd));5280}528152825283void Assembler::rev64(const VRegister& vd, const VRegister& vn) {5284VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5285VIXL_ASSERT(AreSameFormat(vd, vn));5286VIXL_ASSERT(!vd.Is1D() && !vd.Is2D());5287Emit(VFormat(vn) | NEON_REV64 | Rn(vn) | Rd(vd));5288}528952905291void Assembler::ursqrte(const VRegister& vd, const VRegister& vn) {5292VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5293VIXL_ASSERT(AreSameFormat(vd, vn));5294VIXL_ASSERT(vd.Is2S() || vd.Is4S());5295Emit(VFormat(vn) | NEON_URSQRTE | Rn(vn) | Rd(vd));5296}529752985299void Assembler::urecpe(const VRegister& vd, const VRegister& vn) {5300VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5301VIXL_ASSERT(AreSameFormat(vd, vn));5302VIXL_ASSERT(vd.Is2S() || vd.Is4S());5303Emit(VFormat(vn) | NEON_URECPE | Rn(vn) | Rd(vd));5304}530553065307void Assembler::NEONAddlp(const VRegister& vd,5308const VRegister& vn,5309NEON2RegMiscOp op) {5310VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5311VIXL_ASSERT((op == NEON_SADDLP) || (op == NEON_UADDLP) ||5312(op == NEON_SADALP) || (op == NEON_UADALP));53135314VIXL_ASSERT((vn.Is8B() && vd.Is4H()) || (vn.Is4H() && vd.Is2S()) ||5315(vn.Is2S() && vd.Is1D()) || (vn.Is16B() && vd.Is8H()) ||5316(vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));5317Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));5318}531953205321void Assembler::saddlp(const VRegister& vd, const VRegister& vn) {5322VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5323NEONAddlp(vd, vn, NEON_SADDLP);5324}532553265327void Assembler::uaddlp(const VRegister& vd, const VRegister& vn) {5328VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5329NEONAddlp(vd, vn, NEON_UADDLP);5330}533153325333void Assembler::sadalp(const VRegister& vd, const VRegister& vn) {5334VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5335NEONAddlp(vd, vn, NEON_SADALP);5336}533753385339void Assembler::uadalp(const VRegister& vd, const VRegister& vn) {5340VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5341NEONAddlp(vd, vn, NEON_UADALP);5342}534353445345void Assembler::NEONAcrossLanesL(const VRegister& vd,5346const VRegister& vn,5347NEONAcrossLanesOp op) {5348VIXL_ASSERT((vn.Is8B() && vd.Is1H()) || (vn.Is16B() && vd.Is1H()) ||5349(vn.Is4H() && vd.Is1S()) || (vn.Is8H() && vd.Is1S()) ||5350(vn.Is4S() && vd.Is1D()));5351Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));5352}535353545355void Assembler::saddlv(const VRegister& vd, const VRegister& vn) {5356VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5357NEONAcrossLanesL(vd, vn, NEON_SADDLV);5358}535953605361void Assembler::uaddlv(const VRegister& vd, const VRegister& vn) {5362VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5363NEONAcrossLanesL(vd, vn, NEON_UADDLV);5364}536553665367void Assembler::NEONAcrossLanes(const VRegister& vd,5368const VRegister& vn,5369NEONAcrossLanesOp op,5370Instr op_half) {5371VIXL_ASSERT((vn.Is8B() && vd.Is1B()) || (vn.Is16B() && vd.Is1B()) ||5372(vn.Is4H() && vd.Is1H()) || (vn.Is8H() && vd.Is1H()) ||5373(vn.Is4S() && vd.Is1S()));5374if ((op & NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {5375if (vd.Is1H()) {5376VIXL_ASSERT(op_half != 0);5377Instr vop = op_half;5378if (vn.Is8H()) {5379vop |= NEON_Q;5380}5381Emit(vop | Rn(vn) | Rd(vd));5382} else {5383Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd));5384}5385} else {5386Emit(VFormat(vn) | op | Rn(vn) | Rd(vd));5387}5388}53895390// clang-format off5391#define NEON_ACROSSLANES_LIST(V) \5392V(addv, NEON_ADDV) \5393V(smaxv, NEON_SMAXV) \5394V(sminv, NEON_SMINV) \5395V(umaxv, NEON_UMAXV) \5396V(uminv, NEON_UMINV)5397// clang-format on53985399#define VIXL_DEFINE_ASM_FUNC(FN, OP) \5400void Assembler::FN(const VRegister& vd, const VRegister& vn) { \5401VIXL_ASSERT(CPUHas(CPUFeatures::kNEON)); \5402NEONAcrossLanes(vd, vn, OP, 0); \5403}5404NEON_ACROSSLANES_LIST(VIXL_DEFINE_ASM_FUNC)5405#undef VIXL_DEFINE_ASM_FUNC540654075408// clang-format off5409#define NEON_ACROSSLANES_FP_LIST(V) \5410V(fmaxv, NEON_FMAXV, NEON_FMAXV_H) \5411V(fminv, NEON_FMINV, NEON_FMINV_H) \5412V(fmaxnmv, NEON_FMAXNMV, NEON_FMAXNMV_H) \5413V(fminnmv, NEON_FMINNMV, NEON_FMINNMV_H) \5414// clang-format on54155416#define VIXL_DEFINE_ASM_FUNC(FN, OP, OP_H) \5417void Assembler::FN(const VRegister& vd, const VRegister& vn) { \5418VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kNEON)); \5419if (vd.Is1H()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf)); \5420VIXL_ASSERT(vd.Is1S() || vd.Is1H()); \5421NEONAcrossLanes(vd, vn, OP, OP_H); \5422}5423NEON_ACROSSLANES_FP_LIST(VIXL_DEFINE_ASM_FUNC)5424#undef VIXL_DEFINE_ASM_FUNC542554265427void Assembler::NEONPerm(const VRegister& vd,5428const VRegister& vn,5429const VRegister& vm,5430NEONPermOp op) {5431VIXL_ASSERT(AreSameFormat(vd, vn, vm));5432VIXL_ASSERT(!vd.Is1D());5433Emit(VFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd));5434}543554365437void Assembler::trn1(const VRegister& vd,5438const VRegister& vn,5439const VRegister& vm) {5440VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5441NEONPerm(vd, vn, vm, NEON_TRN1);5442}544354445445void Assembler::trn2(const VRegister& vd,5446const VRegister& vn,5447const VRegister& vm) {5448VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5449NEONPerm(vd, vn, vm, NEON_TRN2);5450}545154525453void Assembler::uzp1(const VRegister& vd,5454const VRegister& vn,5455const VRegister& vm) {5456VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5457NEONPerm(vd, vn, vm, NEON_UZP1);5458}545954605461void Assembler::uzp2(const VRegister& vd,5462const VRegister& vn,5463const VRegister& vm) {5464VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5465NEONPerm(vd, vn, vm, NEON_UZP2);5466}546754685469void Assembler::zip1(const VRegister& vd,5470const VRegister& vn,5471const VRegister& vm) {5472VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5473NEONPerm(vd, vn, vm, NEON_ZIP1);5474}547554765477void Assembler::zip2(const VRegister& vd,5478const VRegister& vn,5479const VRegister& vm) {5480VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5481NEONPerm(vd, vn, vm, NEON_ZIP2);5482}548354845485void Assembler::NEONShiftImmediate(const VRegister& vd,5486const VRegister& vn,5487NEONShiftImmediateOp op,5488int immh_immb) {5489VIXL_ASSERT(AreSameFormat(vd, vn));5490Instr q, scalar;5491if (vn.IsScalar()) {5492q = NEON_Q;5493scalar = NEONScalar;5494} else {5495q = vd.IsD() ? 0 : NEON_Q;5496scalar = 0;5497}5498Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));5499}550055015502void Assembler::NEONShiftLeftImmediate(const VRegister& vd,5503const VRegister& vn,5504int shift,5505NEONShiftImmediateOp op) {5506int lane_size_in_bits = vn.GetLaneSizeInBits();5507VIXL_ASSERT((shift >= 0) && (shift < lane_size_in_bits));5508NEONShiftImmediate(vd, vn, op, (lane_size_in_bits + shift) << 16);5509}551055115512void Assembler::NEONShiftRightImmediate(const VRegister& vd,5513const VRegister& vn,5514int shift,5515NEONShiftImmediateOp op) {5516int lane_size_in_bits = vn.GetLaneSizeInBits();5517VIXL_ASSERT((shift >= 1) && (shift <= lane_size_in_bits));5518NEONShiftImmediate(vd, vn, op, ((2 * lane_size_in_bits) - shift) << 16);5519}552055215522void Assembler::NEONShiftImmediateL(const VRegister& vd,5523const VRegister& vn,5524int shift,5525NEONShiftImmediateOp op) {5526int lane_size_in_bits = vn.GetLaneSizeInBits();5527VIXL_ASSERT((shift >= 0) && (shift < lane_size_in_bits));5528int immh_immb = (lane_size_in_bits + shift) << 16;55295530VIXL_ASSERT((vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) ||5531(vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) ||5532(vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D()));5533Instr q;5534q = vn.IsD() ? 0 : NEON_Q;5535Emit(q | op | immh_immb | Rn(vn) | Rd(vd));5536}553755385539void Assembler::NEONShiftImmediateN(const VRegister& vd,5540const VRegister& vn,5541int shift,5542NEONShiftImmediateOp op) {5543Instr q, scalar;5544int lane_size_in_bits = vd.GetLaneSizeInBits();5545VIXL_ASSERT((shift >= 1) && (shift <= lane_size_in_bits));5546int immh_immb = (2 * lane_size_in_bits - shift) << 16;55475548if (vn.IsScalar()) {5549VIXL_ASSERT((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) ||5550(vd.Is1S() && vn.Is1D()));5551q = NEON_Q;5552scalar = NEONScalar;5553} else {5554VIXL_ASSERT((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) ||5555(vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) ||5556(vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D()));5557scalar = 0;5558q = vd.IsD() ? 0 : NEON_Q;5559}5560Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd));5561}556255635564void Assembler::shl(const VRegister& vd, const VRegister& vn, int shift) {5565VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5566VIXL_ASSERT(vd.IsVector() || vd.Is1D());5567NEONShiftLeftImmediate(vd, vn, shift, NEON_SHL);5568}556955705571void Assembler::sli(const VRegister& vd, const VRegister& vn, int shift) {5572VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5573VIXL_ASSERT(vd.IsVector() || vd.Is1D());5574NEONShiftLeftImmediate(vd, vn, shift, NEON_SLI);5575}557655775578void Assembler::sqshl(const VRegister& vd, const VRegister& vn, int shift) {5579VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5580NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHL_imm);5581}558255835584void Assembler::sqshlu(const VRegister& vd, const VRegister& vn, int shift) {5585VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5586NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHLU);5587}558855895590void Assembler::uqshl(const VRegister& vd, const VRegister& vn, int shift) {5591VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5592NEONShiftLeftImmediate(vd, vn, shift, NEON_UQSHL_imm);5593}559455955596void Assembler::sshll(const VRegister& vd, const VRegister& vn, int shift) {5597VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5598VIXL_ASSERT(vn.IsD());5599NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);5600}560156025603void Assembler::sshll2(const VRegister& vd, const VRegister& vn, int shift) {5604VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5605VIXL_ASSERT(vn.IsQ());5606NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL);5607}560856095610void Assembler::sxtl(const VRegister& vd, const VRegister& vn) {5611VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5612sshll(vd, vn, 0);5613}561456155616void Assembler::sxtl2(const VRegister& vd, const VRegister& vn) {5617VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5618sshll2(vd, vn, 0);5619}562056215622void Assembler::ushll(const VRegister& vd, const VRegister& vn, int shift) {5623VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5624VIXL_ASSERT(vn.IsD());5625NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);5626}562756285629void Assembler::ushll2(const VRegister& vd, const VRegister& vn, int shift) {5630VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5631VIXL_ASSERT(vn.IsQ());5632NEONShiftImmediateL(vd, vn, shift, NEON_USHLL);5633}563456355636void Assembler::uxtl(const VRegister& vd, const VRegister& vn) {5637VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5638ushll(vd, vn, 0);5639}564056415642void Assembler::uxtl2(const VRegister& vd, const VRegister& vn) {5643VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5644ushll2(vd, vn, 0);5645}564656475648void Assembler::sri(const VRegister& vd, const VRegister& vn, int shift) {5649VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5650VIXL_ASSERT(vd.IsVector() || vd.Is1D());5651NEONShiftRightImmediate(vd, vn, shift, NEON_SRI);5652}565356545655void Assembler::sshr(const VRegister& vd, const VRegister& vn, int shift) {5656VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5657VIXL_ASSERT(vd.IsVector() || vd.Is1D());5658NEONShiftRightImmediate(vd, vn, shift, NEON_SSHR);5659}566056615662void Assembler::ushr(const VRegister& vd, const VRegister& vn, int shift) {5663VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5664VIXL_ASSERT(vd.IsVector() || vd.Is1D());5665NEONShiftRightImmediate(vd, vn, shift, NEON_USHR);5666}566756685669void Assembler::srshr(const VRegister& vd, const VRegister& vn, int shift) {5670VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5671VIXL_ASSERT(vd.IsVector() || vd.Is1D());5672NEONShiftRightImmediate(vd, vn, shift, NEON_SRSHR);5673}567456755676void Assembler::urshr(const VRegister& vd, const VRegister& vn, int shift) {5677VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5678VIXL_ASSERT(vd.IsVector() || vd.Is1D());5679NEONShiftRightImmediate(vd, vn, shift, NEON_URSHR);5680}568156825683void Assembler::ssra(const VRegister& vd, const VRegister& vn, int shift) {5684VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5685VIXL_ASSERT(vd.IsVector() || vd.Is1D());5686NEONShiftRightImmediate(vd, vn, shift, NEON_SSRA);5687}568856895690void Assembler::usra(const VRegister& vd, const VRegister& vn, int shift) {5691VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5692VIXL_ASSERT(vd.IsVector() || vd.Is1D());5693NEONShiftRightImmediate(vd, vn, shift, NEON_USRA);5694}569556965697void Assembler::srsra(const VRegister& vd, const VRegister& vn, int shift) {5698VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5699VIXL_ASSERT(vd.IsVector() || vd.Is1D());5700NEONShiftRightImmediate(vd, vn, shift, NEON_SRSRA);5701}570257035704void Assembler::ursra(const VRegister& vd, const VRegister& vn, int shift) {5705VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5706VIXL_ASSERT(vd.IsVector() || vd.Is1D());5707NEONShiftRightImmediate(vd, vn, shift, NEON_URSRA);5708}570957105711void Assembler::shrn(const VRegister& vd, const VRegister& vn, int shift) {5712VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5713VIXL_ASSERT(vn.IsVector() && vd.IsD());5714NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);5715}571657175718void Assembler::shrn2(const VRegister& vd, const VRegister& vn, int shift) {5719VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5720VIXL_ASSERT(vn.IsVector() && vd.IsQ());5721NEONShiftImmediateN(vd, vn, shift, NEON_SHRN);5722}572357245725void Assembler::rshrn(const VRegister& vd, const VRegister& vn, int shift) {5726VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5727VIXL_ASSERT(vn.IsVector() && vd.IsD());5728NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);5729}573057315732void Assembler::rshrn2(const VRegister& vd, const VRegister& vn, int shift) {5733VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5734VIXL_ASSERT(vn.IsVector() && vd.IsQ());5735NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN);5736}573757385739void Assembler::sqshrn(const VRegister& vd, const VRegister& vn, int shift) {5740VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5741VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5742NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);5743}574457455746void Assembler::sqshrn2(const VRegister& vd, const VRegister& vn, int shift) {5747VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5748VIXL_ASSERT(vn.IsVector() && vd.IsQ());5749NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN);5750}575157525753void Assembler::sqrshrn(const VRegister& vd, const VRegister& vn, int shift) {5754VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5755VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5756NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);5757}575857595760void Assembler::sqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {5761VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5762VIXL_ASSERT(vn.IsVector() && vd.IsQ());5763NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN);5764}576557665767void Assembler::sqshrun(const VRegister& vd, const VRegister& vn, int shift) {5768VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5769VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5770NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);5771}577257735774void Assembler::sqshrun2(const VRegister& vd, const VRegister& vn, int shift) {5775VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5776VIXL_ASSERT(vn.IsVector() && vd.IsQ());5777NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN);5778}577957805781void Assembler::sqrshrun(const VRegister& vd, const VRegister& vn, int shift) {5782VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5783VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5784NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);5785}578657875788void Assembler::sqrshrun2(const VRegister& vd, const VRegister& vn, int shift) {5789VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5790VIXL_ASSERT(vn.IsVector() && vd.IsQ());5791NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN);5792}579357945795void Assembler::uqshrn(const VRegister& vd, const VRegister& vn, int shift) {5796VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5797VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5798NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);5799}580058015802void Assembler::uqshrn2(const VRegister& vd, const VRegister& vn, int shift) {5803VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5804VIXL_ASSERT(vn.IsVector() && vd.IsQ());5805NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN);5806}580758085809void Assembler::uqrshrn(const VRegister& vd, const VRegister& vn, int shift) {5810VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5811VIXL_ASSERT(vd.IsD() || (vn.IsScalar() && vd.IsScalar()));5812NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);5813}581458155816void Assembler::uqrshrn2(const VRegister& vd, const VRegister& vn, int shift) {5817VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5818VIXL_ASSERT(vn.IsVector() && vd.IsQ());5819NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN);5820}58215822void Assembler::smmla(const VRegister& vd, const VRegister& vn, const VRegister& vm) {5823VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5824VIXL_ASSERT(CPUHas(CPUFeatures::kI8MM));5825VIXL_ASSERT(vd.IsLaneSizeS());5826VIXL_ASSERT(vn.IsLaneSizeB() && vm.IsLaneSizeB());58275828Emit(0x4e80a400 | Rd(vd) | Rn(vn) | Rm(vm));5829}58305831void Assembler::usmmla(const VRegister& vd, const VRegister& vn, const VRegister& vm) {5832VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5833VIXL_ASSERT(CPUHas(CPUFeatures::kI8MM));5834VIXL_ASSERT(vd.IsLaneSizeS());5835VIXL_ASSERT(vn.IsLaneSizeB() && vm.IsLaneSizeB());58365837Emit(0x4e80ac00 | Rd(vd) | Rn(vn) | Rm(vm));5838}58395840void Assembler::ummla(const VRegister& vd, const VRegister& vn, const VRegister& vm) {5841VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));5842VIXL_ASSERT(CPUHas(CPUFeatures::kI8MM));5843VIXL_ASSERT(vd.IsLaneSizeS());5844VIXL_ASSERT(vn.IsLaneSizeB() && vm.IsLaneSizeB());58455846Emit(0x6e80a400 | Rd(vd) | Rn(vn) | Rm(vm));5847}58485849// Note:5850// For all ToImm instructions below, a difference in case5851// for the same letter indicates a negated bit.5852// If b is 1, then B is 0.5853uint32_t Assembler::FP16ToImm8(Float16 imm) {5854VIXL_ASSERT(IsImmFP16(imm));5855// Half: aBbb.cdef.gh00.0000 (16 bits)5856uint16_t bits = Float16ToRawbits(imm);5857// bit7: a000.00005858uint16_t bit7 = ((bits >> 15) & 0x1) << 7;5859// bit6: 0b00.00005860uint16_t bit6 = ((bits >> 13) & 0x1) << 6;5861// bit5_to_0: 00cd.efgh5862uint16_t bit5_to_0 = (bits >> 6) & 0x3f;5863uint32_t result = static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);5864return result;5865}586658675868Instr Assembler::ImmFP16(Float16 imm) {5869return FP16ToImm8(imm) << ImmFP_offset;5870}587158725873uint32_t Assembler::FP32ToImm8(float imm) {5874// bits: aBbb.bbbc.defg.h000.0000.0000.0000.00005875uint32_t bits = FloatToRawbits(imm);5876VIXL_ASSERT(IsImmFP32(bits));5877// bit7: a000.00005878uint32_t bit7 = ((bits >> 31) & 0x1) << 7;5879// bit6: 0b00.00005880uint32_t bit6 = ((bits >> 29) & 0x1) << 6;5881// bit5_to_0: 00cd.efgh5882uint32_t bit5_to_0 = (bits >> 19) & 0x3f;58835884return bit7 | bit6 | bit5_to_0;5885}588658875888Instr Assembler::ImmFP32(float imm) { return FP32ToImm8(imm) << ImmFP_offset; }588958905891uint32_t Assembler::FP64ToImm8(double imm) {5892// bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.00005893// 0000.0000.0000.0000.0000.0000.0000.00005894uint64_t bits = DoubleToRawbits(imm);5895VIXL_ASSERT(IsImmFP64(bits));5896// bit7: a000.00005897uint64_t bit7 = ((bits >> 63) & 0x1) << 7;5898// bit6: 0b00.00005899uint64_t bit6 = ((bits >> 61) & 0x1) << 6;5900// bit5_to_0: 00cd.efgh5901uint64_t bit5_to_0 = (bits >> 48) & 0x3f;59025903return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);5904}590559065907Instr Assembler::ImmFP64(double imm) { return FP64ToImm8(imm) << ImmFP_offset; }590859095910// Code generation helpers.5911bool Assembler::OneInstrMoveImmediateHelper(Assembler* assm,5912const Register& dst,5913uint64_t imm) {5914bool emit_code = assm != NULL;5915unsigned n, imm_s, imm_r;5916int reg_size = dst.GetSizeInBits();59175918if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {5919// Immediate can be represented in a move zero instruction. Movz can't write5920// to the stack pointer.5921if (emit_code) {5922assm->movz(dst, imm);5923}5924return true;5925} else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {5926// Immediate can be represented in a move negative instruction. Movn can't5927// write to the stack pointer.5928if (emit_code) {5929assm->movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));5930}5931return true;5932} else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {5933// Immediate can be represented in a logical orr instruction.5934VIXL_ASSERT(!dst.IsZero());5935if (emit_code) {5936assm->LogicalImmediate(dst,5937AppropriateZeroRegFor(dst),5938n,5939imm_s,5940imm_r,5941ORR);5942}5943return true;5944}5945return false;5946}594759485949void Assembler::MoveWide(const Register& rd,5950uint64_t imm,5951int shift,5952MoveWideImmediateOp mov_op) {5953// Ignore the top 32 bits of an immediate if we're moving to a W register.5954if (rd.Is32Bits()) {5955// Check that the top 32 bits are zero (a positive 32-bit number) or top5956// 33 bits are one (a negative 32-bit number, sign extended to 64 bits).5957VIXL_ASSERT(((imm >> kWRegSize) == 0) ||5958((imm >> (kWRegSize - 1)) == 0x1ffffffff));5959imm &= kWRegMask;5960}59615962if (shift >= 0) {5963// Explicit shift specified.5964VIXL_ASSERT((shift == 0) || (shift == 16) || (shift == 32) ||5965(shift == 48));5966VIXL_ASSERT(rd.Is64Bits() || (shift == 0) || (shift == 16));5967shift /= 16;5968} else {5969// Calculate a new immediate and shift combination to encode the immediate5970// argument.5971VIXL_ASSERT(shift == -1);5972shift = 0;5973if ((imm & 0xffffffffffff0000) == 0) {5974// Nothing to do.5975} else if ((imm & 0xffffffff0000ffff) == 0) {5976imm >>= 16;5977shift = 1;5978} else if ((imm & 0xffff0000ffffffff) == 0) {5979VIXL_ASSERT(rd.Is64Bits());5980imm >>= 32;5981shift = 2;5982} else if ((imm & 0x0000ffffffffffff) == 0) {5983VIXL_ASSERT(rd.Is64Bits());5984imm >>= 48;5985shift = 3;5986}5987}59885989VIXL_ASSERT(IsUint16(imm));59905991Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) | ImmMoveWide(imm) |5992ShiftMoveWide(shift));5993}599459955996void Assembler::AddSub(const Register& rd,5997const Register& rn,5998const Operand& operand,5999FlagsUpdate S,6000AddSubOp op) {6001VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());6002if (operand.IsImmediate()) {6003int64_t immediate = operand.GetImmediate();6004VIXL_ASSERT(IsImmAddSub(immediate));6005Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);6006Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |6007ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn));6008} else if (operand.IsShiftedRegister()) {6009VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());6010VIXL_ASSERT(operand.GetShift() != ROR);60116012// For instructions of the form:6013// add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ]6014// add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ]6015// add/sub wsp, wsp, <Wm> [, LSL #0-3 ]6016// adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]6017// or their 64-bit register equivalents, convert the operand from shifted to6018// extended register mode, and emit an add/sub extended instruction.6019if (rn.IsSP() || rd.IsSP()) {6020VIXL_ASSERT(!(rd.IsSP() && (S == SetFlags)));6021DataProcExtendedRegister(rd,6022rn,6023operand.ToExtendedRegister(),6024S,6025static_cast<Instr>(AddSubExtendedFixed) | static_cast<Instr>(op));6026} else {6027DataProcShiftedRegister(rd, rn, operand, S,6028static_cast<Instr>(AddSubShiftedFixed) | static_cast<Instr>(op));6029}6030} else {6031VIXL_ASSERT(operand.IsExtendedRegister());6032DataProcExtendedRegister(rd, rn, operand, S,6033static_cast<Instr>(AddSubExtendedFixed) | static_cast<Instr>(op));6034}6035}603660376038void Assembler::AddSubWithCarry(const Register& rd,6039const Register& rn,6040const Operand& operand,6041FlagsUpdate S,6042AddSubWithCarryOp op) {6043VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());6044VIXL_ASSERT(rd.GetSizeInBits() == operand.GetRegister().GetSizeInBits());6045VIXL_ASSERT(operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0));6046Emit(SF(rd) | op | Flags(S) | Rm(operand.GetRegister()) | Rn(rn) | Rd(rd));6047}604860496050void Assembler::hlt(int code) {6051VIXL_ASSERT(IsUint16(code));6052Emit(HLT | ImmException(code));6053}605460556056void Assembler::brk(int code) {6057VIXL_ASSERT(IsUint16(code));6058Emit(BRK | ImmException(code));6059}606060616062void Assembler::svc(int code) { Emit(SVC | ImmException(code)); }60636064void Assembler::udf(int code) { Emit(UDF | ImmUdf(code)); }606560666067// TODO(all): The third parameter should be passed by reference but gcc 4.8.26068// reports a bogus uninitialised warning then.6069void Assembler::Logical(const Register& rd,6070const Register& rn,6071const Operand operand,6072LogicalOp op) {6073VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());6074if (operand.IsImmediate()) {6075int64_t immediate = operand.GetImmediate();6076unsigned reg_size = rd.GetSizeInBits();60776078VIXL_ASSERT(immediate != 0);6079VIXL_ASSERT(immediate != -1);6080VIXL_ASSERT(rd.Is64Bits() || IsUint32(immediate));60816082// If the operation is NOT, invert the operation and immediate.6083if ((op & NOT) == NOT) {6084op = static_cast<LogicalOp>(op & ~NOT);6085immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);6086}60876088unsigned n, imm_s, imm_r;6089if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {6090// Immediate can be encoded in the instruction.6091LogicalImmediate(rd, rn, n, imm_s, imm_r, op);6092} else {6093// This case is handled in the macro assembler.6094VIXL_UNREACHABLE();6095}6096} else {6097VIXL_ASSERT(operand.IsShiftedRegister());6098VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());6099Instr dp_op = static_cast<Instr>(op) | static_cast<Instr>(LogicalShiftedFixed);6100DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);6101}6102}610361046105void Assembler::LogicalImmediate(const Register& rd,6106const Register& rn,6107unsigned n,6108unsigned imm_s,6109unsigned imm_r,6110LogicalOp op) {6111unsigned reg_size = rd.GetSizeInBits();6112Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);6113Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |6114ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |6115Rn(rn));6116}611761186119void Assembler::ConditionalCompare(const Register& rn,6120const Operand& operand,6121StatusFlags nzcv,6122Condition cond,6123ConditionalCompareOp op) {6124Instr ccmpop;6125if (operand.IsImmediate()) {6126int64_t immediate = operand.GetImmediate();6127VIXL_ASSERT(IsImmConditionalCompare(immediate));6128ccmpop = static_cast<Instr>(ConditionalCompareImmediateFixed) |6129static_cast<Instr>(op) |6130ImmCondCmp(static_cast<unsigned>(immediate));6131} else {6132VIXL_ASSERT(operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0));6133ccmpop = static_cast<Instr>(ConditionalCompareRegisterFixed) |6134static_cast<Instr>(op) |6135Rm(operand.GetRegister());6136}6137Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));6138}613961406141void Assembler::DataProcessing1Source(const Register& rd,6142const Register& rn,6143DataProcessing1SourceOp op) {6144VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());6145Emit(SF(rn) | op | Rn(rn) | Rd(rd));6146}614761486149void Assembler::FPDataProcessing1Source(const VRegister& vd,6150const VRegister& vn,6151FPDataProcessing1SourceOp op) {6152VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());6153Emit(FPType(vn) | op | Rn(vn) | Rd(vd));6154}615561566157void Assembler::FPDataProcessing3Source(const VRegister& vd,6158const VRegister& vn,6159const VRegister& vm,6160const VRegister& va,6161FPDataProcessing3SourceOp op) {6162VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());6163VIXL_ASSERT(AreSameSizeAndType(vd, vn, vm, va));6164Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd) | Ra(va));6165}616661676168void Assembler::NEONModifiedImmShiftLsl(const VRegister& vd,6169const int imm8,6170const int left_shift,6171NEONModifiedImmediateOp op) {6172VIXL_ASSERT(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H() || vd.Is2S() ||6173vd.Is4S());6174VIXL_ASSERT((left_shift == 0) || (left_shift == 8) || (left_shift == 16) ||6175(left_shift == 24));6176VIXL_ASSERT(IsUint8(imm8));61776178int cmode_1, cmode_2, cmode_3;6179if (vd.Is8B() || vd.Is16B()) {6180VIXL_ASSERT(op == NEONModifiedImmediate_MOVI);6181cmode_1 = 1;6182cmode_2 = 1;6183cmode_3 = 1;6184} else {6185cmode_1 = (left_shift >> 3) & 1;6186cmode_2 = left_shift >> 4;6187cmode_3 = 0;6188if (vd.Is4H() || vd.Is8H()) {6189VIXL_ASSERT((left_shift == 0) || (left_shift == 8));6190cmode_3 = 1;6191}6192}6193int cmode = (cmode_3 << 3) | (cmode_2 << 2) | (cmode_1 << 1);61946195int q = vd.IsQ() ? NEON_Q : 0;61966197Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));6198}619962006201void Assembler::NEONModifiedImmShiftMsl(const VRegister& vd,6202const int imm8,6203const int shift_amount,6204NEONModifiedImmediateOp op) {6205VIXL_ASSERT(vd.Is2S() || vd.Is4S());6206VIXL_ASSERT((shift_amount == 8) || (shift_amount == 16));6207VIXL_ASSERT(IsUint8(imm8));62086209int cmode_0 = (shift_amount >> 4) & 1;6210int cmode = 0xc | cmode_0;62116212int q = vd.IsQ() ? NEON_Q : 0;62136214Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd));6215}621662176218void Assembler::EmitShift(const Register& rd,6219const Register& rn,6220Shift shift,6221unsigned shift_amount) {6222switch (shift) {6223case LSL:6224lsl(rd, rn, shift_amount);6225break;6226case LSR:6227lsr(rd, rn, shift_amount);6228break;6229case ASR:6230asr(rd, rn, shift_amount);6231break;6232case ROR:6233ror(rd, rn, shift_amount);6234break;6235default:6236VIXL_UNREACHABLE();6237}6238}623962406241void Assembler::EmitExtendShift(const Register& rd,6242const Register& rn,6243Extend extend,6244unsigned left_shift) {6245VIXL_ASSERT(rd.GetSizeInBits() >= rn.GetSizeInBits());6246unsigned reg_size = rd.GetSizeInBits();6247// Use the correct size of register.6248Register rn_ = Register(rn.GetCode(), rd.GetSizeInBits());6249// Bits extracted are high_bit:0.6250unsigned high_bit = (8 << (extend & 0x3)) - 1;6251// Number of bits left in the result that are not introduced by the shift.6252unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);62536254if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {6255switch (extend) {6256case UXTB:6257case UXTH:6258case UXTW:6259ubfm(rd, rn_, non_shift_bits, high_bit);6260break;6261case SXTB:6262case SXTH:6263case SXTW:6264sbfm(rd, rn_, non_shift_bits, high_bit);6265break;6266case UXTX:6267case SXTX: {6268VIXL_ASSERT(rn.GetSizeInBits() == kXRegSize);6269// Nothing to extend. Just shift.6270lsl(rd, rn_, left_shift);6271break;6272}6273default:6274VIXL_UNREACHABLE();6275}6276} else {6277// No need to extend as the extended bits would be shifted away.6278lsl(rd, rn_, left_shift);6279}6280}628162826283void Assembler::DataProcShiftedRegister(const Register& rd,6284const Register& rn,6285const Operand& operand,6286FlagsUpdate S,6287Instr op) {6288VIXL_ASSERT(operand.IsShiftedRegister());6289VIXL_ASSERT(rn.Is64Bits() ||6290(rn.Is32Bits() && IsUint5(operand.GetShiftAmount())));6291Emit(SF(rd) | op | Flags(S) | ShiftDP(operand.GetShift()) |6292ImmDPShift(operand.GetShiftAmount()) | Rm(operand.GetRegister()) |6293Rn(rn) | Rd(rd));6294}629562966297void Assembler::DataProcExtendedRegister(const Register& rd,6298const Register& rn,6299const Operand& operand,6300FlagsUpdate S,6301Instr op) {6302Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);6303Emit(SF(rd) | op | Flags(S) | Rm(operand.GetRegister()) |6304ExtendMode(operand.GetExtend()) |6305ImmExtendShift(operand.GetShiftAmount()) | dest_reg | RnSP(rn));6306}630763086309Instr Assembler::LoadStoreMemOperand(const MemOperand& addr,6310unsigned access_size_in_bytes_log2,6311LoadStoreScalingOption option) {6312Instr base = RnSP(addr.GetBaseRegister());6313int64_t offset = addr.GetOffset();63146315if (addr.IsImmediateOffset()) {6316bool prefer_unscaled =6317(option == PreferUnscaledOffset) || (option == RequireUnscaledOffset);6318if (prefer_unscaled && IsImmLSUnscaled(offset)) {6319// Use the unscaled addressing mode.6320return base | LoadStoreUnscaledOffsetFixed | ImmLS(offset);6321}63226323if ((option != RequireUnscaledOffset) &&6324IsImmLSScaled(offset, access_size_in_bytes_log2)) {6325// We need `offset` to be positive for the shift to be well-defined.6326// IsImmLSScaled should check this.6327VIXL_ASSERT(offset >= 0);6328// Use the scaled addressing mode.6329return base | LoadStoreUnsignedOffsetFixed |6330ImmLSUnsigned(offset >> access_size_in_bytes_log2);6331}63326333if ((option != RequireScaledOffset) && IsImmLSUnscaled(offset)) {6334// Use the unscaled addressing mode.6335return base | LoadStoreUnscaledOffsetFixed | ImmLS(offset);6336}6337}63386339// All remaining addressing modes are register-offset, pre-indexed or6340// post-indexed modes.6341VIXL_ASSERT((option != RequireUnscaledOffset) &&6342(option != RequireScaledOffset));63436344if (addr.IsRegisterOffset()) {6345Extend ext = addr.GetExtend();6346Shift shift = addr.GetShift();6347unsigned shift_amount = addr.GetShiftAmount();63486349// LSL is encoded in the option field as UXTX.6350if (shift == LSL) {6351ext = UXTX;6352}63536354// Shifts are encoded in one bit, indicating a left shift by the memory6355// access size.6356VIXL_ASSERT((shift_amount == 0) || (shift_amount == access_size_in_bytes_log2));6357return base | LoadStoreRegisterOffsetFixed | Rm(addr.GetRegisterOffset()) |6358ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0);6359}63606361if (addr.IsImmediatePreIndex() && IsImmLSUnscaled(offset)) {6362return base | LoadStorePreIndexFixed | ImmLS(offset);6363}63646365if (addr.IsImmediatePostIndex() && IsImmLSUnscaled(offset)) {6366return base | LoadStorePostIndexFixed | ImmLS(offset);6367}63686369// If this point is reached, the MemOperand (addr) cannot be encoded.6370VIXL_UNREACHABLE();6371return 0;6372}637363746375void Assembler::LoadStore(const CPURegister& rt,6376const MemOperand& addr,6377LoadStoreOp op,6378LoadStoreScalingOption option) {6379VIXL_ASSERT(CPUHas(rt));6380Emit(op | Rt(rt) | LoadStoreMemOperand(addr, CalcLSDataSize(op), option));6381}63826383void Assembler::LoadStorePAC(const Register& xt,6384const MemOperand& addr,6385LoadStorePACOp op) {6386VIXL_ASSERT(xt.Is64Bits());6387VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsImmediatePreIndex());63886389Instr pac_op = op;6390if (addr.IsImmediatePreIndex()) {6391pac_op |= LoadStorePACPreBit;6392}63936394Instr base = RnSP(addr.GetBaseRegister());6395int64_t offset = addr.GetOffset();63966397Emit(pac_op | Rt(xt) | base | ImmLSPAC(static_cast<int>(offset)));6398}639964006401void Assembler::Prefetch(int op,6402const MemOperand& addr,6403LoadStoreScalingOption option) {6404VIXL_ASSERT(addr.IsRegisterOffset() || addr.IsImmediateOffset());64056406Instr prfop = ImmPrefetchOperation(op);6407Emit(PRFM | prfop | LoadStoreMemOperand(addr, kXRegSizeInBytesLog2, option));6408}64096410void Assembler::Prefetch(PrefetchOperation op,6411const MemOperand& addr,6412LoadStoreScalingOption option) {6413// Passing unnamed values in 'op' is undefined behaviour in C++.6414VIXL_ASSERT(IsNamedPrefetchOperation(op));6415Prefetch(static_cast<int>(op), addr, option);6416}641764186419bool Assembler::IsImmAddSub(int64_t immediate) {6420return IsUint12(immediate) ||6421(IsUint12(immediate >> 12) && ((immediate & 0xfff) == 0));6422}642364246425bool Assembler::IsImmConditionalCompare(int64_t immediate) {6426return IsUint5(immediate);6427}642864296430bool Assembler::IsImmFP16(Float16 imm) {6431// Valid values will have the form:6432// aBbb.cdef.gh00.0006433uint16_t bits = Float16ToRawbits(imm);6434// bits[6..0] are cleared.6435if ((bits & 0x3f) != 0) {6436return false;6437}64386439// bits[13..12] are all set or all cleared.6440uint16_t b_pattern = (bits >> 12) & 0x03;6441if (b_pattern != 0 && b_pattern != 0x03) {6442return false;6443}64446445// bit[15] and bit[14] are opposite.6446if (((bits ^ (bits << 1)) & 0x4000) == 0) {6447return false;6448}64496450return true;6451}645264536454bool Assembler::IsImmFP32(uint32_t bits) {6455// Valid values will have the form:6456// aBbb.bbbc.defg.h000.0000.0000.0000.00006457// bits[19..0] are cleared.6458if ((bits & 0x7ffff) != 0) {6459return false;6460}64616462// bits[29..25] are all set or all cleared.6463uint32_t b_pattern = (bits >> 16) & 0x3e00;6464if (b_pattern != 0 && b_pattern != 0x3e00) {6465return false;6466}64676468// bit[30] and bit[29] are opposite.6469if (((bits ^ (bits << 1)) & 0x40000000) == 0) {6470return false;6471}64726473return true;6474}647564766477bool Assembler::IsImmFP64(uint64_t bits) {6478// Valid values will have the form:6479// aBbb.bbbb.bbcd.efgh.0000.0000.0000.00006480// 0000.0000.0000.0000.0000.0000.0000.00006481// bits[47..0] are cleared.6482if ((bits & 0x0000ffffffffffff) != 0) {6483return false;6484}64856486// bits[61..54] are all set or all cleared.6487uint32_t b_pattern = (bits >> 48) & 0x3fc0;6488if ((b_pattern != 0) && (b_pattern != 0x3fc0)) {6489return false;6490}64916492// bit[62] and bit[61] are opposite.6493if (((bits ^ (bits << 1)) & (UINT64_C(1) << 62)) == 0) {6494return false;6495}64966497return true;6498}649965006501bool Assembler::IsImmLSPair(int64_t offset, unsigned access_size_in_bytes_log2) {6502const auto access_size_in_bytes = 1U << access_size_in_bytes_log2;6503VIXL_ASSERT(access_size_in_bytes_log2 <= kQRegSizeInBytesLog2);6504return IsMultiple(offset, access_size_in_bytes) &&6505IsInt7(offset / access_size_in_bytes);6506}650765086509bool Assembler::IsImmLSScaled(int64_t offset, unsigned access_size_in_bytes_log2) {6510const auto access_size_in_bytes = 1U << access_size_in_bytes_log2;6511VIXL_ASSERT(access_size_in_bytes_log2 <= kQRegSizeInBytesLog2);6512return IsMultiple(offset, access_size_in_bytes) &&6513IsUint12(offset / access_size_in_bytes);6514}651565166517bool Assembler::IsImmLSUnscaled(int64_t offset) { return IsInt9(offset); }651865196520// The movn instruction can generate immediates containing an arbitrary 16-bit6521// value, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff.6522bool Assembler::IsImmMovn(uint64_t imm, unsigned reg_size) {6523return IsImmMovz(~imm, reg_size);6524}652565266527// The movz instruction can generate immediates containing an arbitrary 16-bit6528// value, with remaining bits clear, eg. 0x00001234, 0x0000123400000000.6529bool Assembler::IsImmMovz(uint64_t imm, unsigned reg_size) {6530VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));6531return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1);6532}653365346535// Test if a given value can be encoded in the immediate field of a logical6536// instruction.6537// If it can be encoded, the function returns true, and values pointed to by n,6538// imm_s and imm_r are updated with immediates encoded in the format required6539// by the corresponding fields in the logical instruction.6540// If it can not be encoded, the function returns false, and the values pointed6541// to by n, imm_s and imm_r are undefined.6542bool Assembler::IsImmLogical(uint64_t value,6543unsigned width,6544unsigned* n,6545unsigned* imm_s,6546unsigned* imm_r) {6547VIXL_ASSERT((width == kBRegSize) || (width == kHRegSize) ||6548(width == kSRegSize) || (width == kDRegSize));65496550bool negate = false;65516552// Logical immediates are encoded using parameters n, imm_s and imm_r using6553// the following table:6554//6555// N imms immr size S R6556// 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)6557// 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)6558// 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)6559// 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)6560// 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)6561// 0 11110s xxxxxr 2 UInt(s) UInt(r)6562// (s bits must not be all set)6563//6564// A pattern is constructed of size bits, where the least significant S+1 bits6565// are set. The pattern is rotated right by R, and repeated across a 32 or6566// 64-bit value, depending on destination register width.6567//6568// Put another way: the basic format of a logical immediate is a single6569// contiguous stretch of 1 bits, repeated across the whole word at intervals6570// given by a power of 2. To identify them quickly, we first locate the6571// lowest stretch of 1 bits, then the next 1 bit above that; that combination6572// is different for every logical immediate, so it gives us all the6573// information we need to identify the only logical immediate that our input6574// could be, and then we simply check if that's the value we actually have.6575//6576// (The rotation parameter does give the possibility of the stretch of 1 bits6577// going 'round the end' of the word. To deal with that, we observe that in6578// any situation where that happens the bitwise NOT of the value is also a6579// valid logical immediate. So we simply invert the input whenever its low bit6580// is set, and then we know that the rotated case can't arise.)65816582if (value & 1) {6583// If the low bit is 1, negate the value, and set a flag to remember that we6584// did (so that we can adjust the return values appropriately).6585negate = true;6586value = ~value;6587}65886589if (width <= kWRegSize) {6590// To handle 8/16/32-bit logical immediates, the very easiest thing is to repeat6591// the input value to fill a 64-bit word. The correct encoding of that as a6592// logical immediate will also be the correct encoding of the value.65936594// Avoid making the assumption that the most-significant 56/48/32 bits are zero by6595// shifting the value left and duplicating it.6596for (unsigned bits = width; bits <= kWRegSize; bits *= 2) {6597value <<= bits;6598uint64_t mask = (UINT64_C(1) << bits) - 1;6599value |= ((value >> bits) & mask);6600}6601}66026603// The basic analysis idea: imagine our input word looks like this.6604//6605// 00111110001111100011111000111110001111100011111000111110001111106606// c b a6607// |<--d-->|6608//6609// We find the lowest set bit (as an actual power-of-2 value, not its index)6610// and call it a. Then we add a to our original number, which wipes out the6611// bottommost stretch of set bits and replaces it with a 1 carried into the6612// next zero bit. Then we look for the new lowest set bit, which is in6613// position b, and subtract it, so now our number is just like the original6614// but with the lowest stretch of set bits completely gone. Now we find the6615// lowest set bit again, which is position c in the diagram above. Then we'll6616// measure the distance d between bit positions a and c (using CLZ), and that6617// tells us that the only valid logical immediate that could possibly be equal6618// to this number is the one in which a stretch of bits running from a to just6619// below b is replicated every d bits.6620uint64_t a = LowestSetBit(value);6621uint64_t value_plus_a = value + a;6622uint64_t b = LowestSetBit(value_plus_a);6623uint64_t value_plus_a_minus_b = value_plus_a - b;6624uint64_t c = LowestSetBit(value_plus_a_minus_b);66256626int d, clz_a, out_n;6627uint64_t mask;66286629if (c != 0) {6630// The general case, in which there is more than one stretch of set bits.6631// Compute the repeat distance d, and set up a bitmask covering the basic6632// unit of repetition (i.e. a word with the bottom d bits set). Also, in all6633// of these cases the N bit of the output will be zero.6634clz_a = CountLeadingZeros(a, kXRegSize);6635int clz_c = CountLeadingZeros(c, kXRegSize);6636d = clz_a - clz_c;6637mask = ((UINT64_C(1) << d) - 1);6638out_n = 0;6639} else {6640// Handle degenerate cases.6641//6642// If any of those 'find lowest set bit' operations didn't find a set bit at6643// all, then the word will have been zero thereafter, so in particular the6644// last lowest_set_bit operation will have returned zero. So we can test for6645// all the special case conditions in one go by seeing if c is zero.6646if (a == 0) {6647// The input was zero (or all 1 bits, which will come to here too after we6648// inverted it at the start of the function), for which we just return6649// false.6650return false;6651} else {6652// Otherwise, if c was zero but a was not, then there's just one stretch6653// of set bits in our word, meaning that we have the trivial case of6654// d == 64 and only one 'repetition'. Set up all the same variables as in6655// the general case above, and set the N bit in the output.6656clz_a = CountLeadingZeros(a, kXRegSize);6657d = 64;6658mask = ~UINT64_C(0);6659out_n = 1;6660}6661}66626663// If the repeat period d is not a power of two, it can't be encoded.6664if (!IsPowerOf2(d)) {6665return false;6666}66676668if (((b - a) & ~mask) != 0) {6669// If the bit stretch (b - a) does not fit within the mask derived from the6670// repeat period, then fail.6671return false;6672}66736674// The only possible option is b - a repeated every d bits. Now we're going to6675// actually construct the valid logical immediate derived from that6676// specification, and see if it equals our original input.6677//6678// To repeat a value every d bits, we multiply it by a number of the form6679// (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can6680// be derived using a table lookup on CLZ(d).6681static const uint64_t multipliers[] = {66820x0000000000000001UL,66830x0000000100000001UL,66840x0001000100010001UL,66850x0101010101010101UL,66860x1111111111111111UL,66870x5555555555555555UL,6688};6689uint64_t multiplier = multipliers[CountLeadingZeros(d, kXRegSize) - 57];6690uint64_t candidate = (b - a) * multiplier;66916692if (value != candidate) {6693// The candidate pattern doesn't match our input value, so fail.6694return false;6695}66966697// We have a match! This is a valid logical immediate, so now we have to6698// construct the bits and pieces of the instruction encoding that generates6699// it.67006701// Count the set bits in our basic stretch. The special case of clz(0) == -16702// makes the answer come out right for stretches that reach the very top of6703// the word (e.g. numbers like 0xffffc00000000000).6704int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSize);6705int s = clz_a - clz_b;67066707// Decide how many bits to rotate right by, to put the low bit of that basic6708// stretch in position a.6709int r;6710if (negate) {6711// If we inverted the input right at the start of this function, here's6712// where we compensate: the number of set bits becomes the number of clear6713// bits, and the rotation count is based on position b rather than position6714// a (since b is the location of the 'lowest' 1 bit after inversion).6715s = d - s;6716r = (clz_b + 1) & (d - 1);6717} else {6718r = (clz_a + 1) & (d - 1);6719}67206721// Now we're done, except for having to encode the S output in such a way that6722// it gives both the number of set bits and the length of the repeated6723// segment. The s field is encoded like this:6724//6725// imms size S6726// ssssss 64 UInt(ssssss)6727// 0sssss 32 UInt(sssss)6728// 10ssss 16 UInt(ssss)6729// 110sss 8 UInt(sss)6730// 1110ss 4 UInt(ss)6731// 11110s 2 UInt(s)6732//6733// So we 'or' (2 * -d) with our computed s to form imms.6734if ((n != NULL) || (imm_s != NULL) || (imm_r != NULL)) {6735*n = out_n;6736*imm_s = ((2 * -d) | (s - 1)) & 0x3f;6737*imm_r = r;6738}67396740return true;6741}674267436744LoadStoreOp Assembler::LoadOpFor(const CPURegister& rt) {6745VIXL_ASSERT(rt.IsValid());6746if (rt.IsRegister()) {6747return rt.Is64Bits() ? LDR_x : LDR_w;6748} else {6749VIXL_ASSERT(rt.IsVRegister());6750switch (rt.GetSizeInBits()) {6751case kBRegSize:6752return LDR_b;6753case kHRegSize:6754return LDR_h;6755case kSRegSize:6756return LDR_s;6757case kDRegSize:6758return LDR_d;6759default:6760VIXL_ASSERT(rt.IsQ());6761return LDR_q;6762}6763}6764}676567666767LoadStoreOp Assembler::StoreOpFor(const CPURegister& rt) {6768VIXL_ASSERT(rt.IsValid());6769if (rt.IsRegister()) {6770return rt.Is64Bits() ? STR_x : STR_w;6771} else {6772VIXL_ASSERT(rt.IsVRegister());6773switch (rt.GetSizeInBits()) {6774case kBRegSize:6775return STR_b;6776case kHRegSize:6777return STR_h;6778case kSRegSize:6779return STR_s;6780case kDRegSize:6781return STR_d;6782default:6783VIXL_ASSERT(rt.IsQ());6784return STR_q;6785}6786}6787}678867896790LoadStorePairOp Assembler::StorePairOpFor(const CPURegister& rt,6791const CPURegister& rt2) {6792VIXL_ASSERT(AreSameSizeAndType(rt, rt2));6793USE(rt2);6794if (rt.IsRegister()) {6795return rt.Is64Bits() ? STP_x : STP_w;6796} else {6797VIXL_ASSERT(rt.IsVRegister());6798switch (rt.GetSizeInBytes()) {6799case kSRegSizeInBytes:6800return STP_s;6801case kDRegSizeInBytes:6802return STP_d;6803default:6804VIXL_ASSERT(rt.IsQ());6805return STP_q;6806}6807}6808}680968106811LoadStorePairOp Assembler::LoadPairOpFor(const CPURegister& rt,6812const CPURegister& rt2) {6813VIXL_ASSERT((STP_w | LoadStorePairLBit) == LDP_w);6814return static_cast<LoadStorePairOp>(StorePairOpFor(rt, rt2) |6815LoadStorePairLBit);6816}681768186819LoadStorePairNonTemporalOp Assembler::StorePairNonTemporalOpFor(6820const CPURegister& rt, const CPURegister& rt2) {6821VIXL_ASSERT(AreSameSizeAndType(rt, rt2));6822USE(rt2);6823if (rt.IsRegister()) {6824return rt.Is64Bits() ? STNP_x : STNP_w;6825} else {6826VIXL_ASSERT(rt.IsVRegister());6827switch (rt.GetSizeInBytes()) {6828case kSRegSizeInBytes:6829return STNP_s;6830case kDRegSizeInBytes:6831return STNP_d;6832default:6833VIXL_ASSERT(rt.IsQ());6834return STNP_q;6835}6836}6837}683868396840LoadStorePairNonTemporalOp Assembler::LoadPairNonTemporalOpFor(6841const CPURegister& rt, const CPURegister& rt2) {6842VIXL_ASSERT((STNP_w | LoadStorePairNonTemporalLBit) == LDNP_w);6843return static_cast<LoadStorePairNonTemporalOp>(6844StorePairNonTemporalOpFor(rt, rt2) | LoadStorePairNonTemporalLBit);6845}684668476848LoadLiteralOp Assembler::LoadLiteralOpFor(const CPURegister& rt) {6849if (rt.IsRegister()) {6850return rt.IsX() ? LDR_x_lit : LDR_w_lit;6851} else {6852VIXL_ASSERT(rt.IsVRegister());6853switch (rt.GetSizeInBytes()) {6854case kSRegSizeInBytes:6855return LDR_s_lit;6856case kDRegSizeInBytes:6857return LDR_d_lit;6858default:6859VIXL_ASSERT(rt.IsQ());6860return LDR_q_lit;6861}6862}6863}686468656866bool Assembler::CPUHas(const CPURegister& rt) const {6867// Core registers are available without any particular CPU features.6868if (rt.IsRegister()) return true;6869VIXL_ASSERT(rt.IsVRegister());6870// The architecture does not allow FP and NEON to be implemented separately,6871// but we can crudely categorise them based on register size, since FP only6872// uses D, S and (occasionally) H registers.6873if (rt.IsH() || rt.IsS() || rt.IsD()) {6874return CPUHas(CPUFeatures::kFP) || CPUHas(CPUFeatures::kNEON);6875}6876VIXL_ASSERT(rt.IsB() || rt.IsQ());6877return CPUHas(CPUFeatures::kNEON);6878}687968806881bool Assembler::CPUHas(const CPURegister& rt, const CPURegister& rt2) const {6882// This is currently only used for loads and stores, where rt and rt2 must6883// have the same size and type. We could extend this to cover other cases if6884// necessary, but for now we can avoid checking both registers.6885VIXL_ASSERT(AreSameSizeAndType(rt, rt2));6886USE(rt2);6887return CPUHas(rt);6888}688968906891bool Assembler::CPUHas(SystemRegister sysreg) const {6892switch (sysreg) {6893case RNDR:6894case RNDRRS:6895return CPUHas(CPUFeatures::kRNG);6896case FPCR:6897case NZCV:6898break;6899}6900return true;6901}690269036904} // namespace aarch646905} // namespace vixl690669076908