// Copyright 2015, VIXL authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef VIXL_AARCH64_MACRO_ASSEMBLER_AARCH64_H_ #define VIXL_AARCH64_MACRO_ASSEMBLER_AARCH64_H_ #include #include #include "../code-generation-scopes-vixl.h" #include "../globals-vixl.h" #include "../macro-assembler-interface.h" #include "assembler-aarch64.h" // Required for runtime call support. // TODO: Break this dependency. We should be able to separate out the necessary // parts so that we don't need to include the whole simulator header. #include "simulator-aarch64.h" // Required in order to generate debugging instructions for the simulator. This // is needed regardless of whether the simulator is included or not, since // generating simulator specific instructions is controlled at runtime. #include "simulator-constants-aarch64.h" #define LS_MACRO_LIST(V) \ V(Ldrb, Register&, rt, LDRB_w) \ V(Strb, Register&, rt, STRB_w) \ V(Ldrsb, Register&, rt, rt.Is64Bits() ? LDRSB_x : LDRSB_w) \ V(Ldrh, Register&, rt, LDRH_w) \ V(Strh, Register&, rt, STRH_w) \ V(Ldrsh, Register&, rt, rt.Is64Bits() ? LDRSH_x : LDRSH_w) \ V(Ldr, CPURegister&, rt, LoadOpFor(rt)) \ V(Str, CPURegister&, rt, StoreOpFor(rt)) \ V(Ldrsw, Register&, rt, LDRSW_x) #define LSPAIR_MACRO_LIST(V) \ V(Ldp, CPURegister&, rt, rt2, LoadPairOpFor(rt, rt2)) \ V(Stp, CPURegister&, rt, rt2, StorePairOpFor(rt, rt2)) \ V(Ldpsw, Register&, rt, rt2, LDPSW_x) namespace vixl { namespace aarch64 { // Forward declaration class MacroAssembler; class UseScratchRegisterScope; class Pool { public: explicit Pool(MacroAssembler* masm) : checkpoint_(kNoCheckpointRequired), masm_(masm) { Reset(); } void Reset() { checkpoint_ = kNoCheckpointRequired; monitor_ = 0; } void Block() { monitor_++; } void Release(); bool IsBlocked() const { return monitor_ != 0; } static const ptrdiff_t kNoCheckpointRequired = PTRDIFF_MAX; void SetNextCheckpoint(ptrdiff_t checkpoint); ptrdiff_t GetCheckpoint() const { return checkpoint_; } VIXL_DEPRECATED("GetCheckpoint", ptrdiff_t checkpoint() const) { return GetCheckpoint(); } enum EmitOption { kBranchRequired, kNoBranchRequired }; protected: // Next buffer offset at which a check is required for this pool. ptrdiff_t checkpoint_; // Indicates whether the emission of this pool is blocked. int monitor_; // The MacroAssembler using this pool. MacroAssembler* masm_; }; class LiteralPool : public Pool { public: explicit LiteralPool(MacroAssembler* masm); ~LiteralPool() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION; void Reset(); void AddEntry(RawLiteral* literal); bool IsEmpty() const { return entries_.empty(); } size_t GetSize() const; VIXL_DEPRECATED("GetSize", size_t Size() const) { return GetSize(); } size_t GetMaxSize() const; VIXL_DEPRECATED("GetMaxSize", size_t MaxSize() const) { return GetMaxSize(); } size_t GetOtherPoolsMaxSize() const; VIXL_DEPRECATED("GetOtherPoolsMaxSize", size_t OtherPoolsMaxSize() const) { return GetOtherPoolsMaxSize(); } void CheckEmitFor(size_t amount, EmitOption option = kBranchRequired); // Check whether we need to emit the literal pool in order to be able to // safely emit a branch with a given range. void CheckEmitForBranch(size_t range); void Emit(EmitOption option = kNoBranchRequired); void SetNextRecommendedCheckpoint(ptrdiff_t offset); ptrdiff_t GetNextRecommendedCheckpoint(); VIXL_DEPRECATED("GetNextRecommendedCheckpoint", ptrdiff_t NextRecommendedCheckpoint()) { return GetNextRecommendedCheckpoint(); } void UpdateFirstUse(ptrdiff_t use_position); void DeleteOnDestruction(RawLiteral* literal) { deleted_on_destruction_.push_back(literal); } // Recommended not exact since the pool can be blocked for short periods. static const ptrdiff_t kRecommendedLiteralPoolRange = 128 * KBytes; private: std::vector entries_; size_t size_; ptrdiff_t first_use_; // The parent class `Pool` provides a `checkpoint_`, which is the buffer // offset before which a check *must* occur. This recommended checkpoint // indicates when we would like to start emitting the constant pool. The // MacroAssembler can, but does not have to, check the buffer when the // checkpoint is reached. ptrdiff_t recommended_checkpoint_; std::vector deleted_on_destruction_; }; inline size_t LiteralPool::GetSize() const { // Account for the pool header. return size_ + kInstructionSize; } inline size_t LiteralPool::GetMaxSize() const { // Account for the potential branch over the pool. return GetSize() + kInstructionSize; } inline ptrdiff_t LiteralPool::GetNextRecommendedCheckpoint() { return first_use_ + kRecommendedLiteralPoolRange; } class VeneerPool : public Pool { public: explicit VeneerPool(MacroAssembler* masm) : Pool(masm) {} void Reset(); void Block() { monitor_++; } void Release(); bool IsBlocked() const { return monitor_ != 0; } bool IsEmpty() const { return unresolved_branches_.IsEmpty(); } class BranchInfo { public: BranchInfo() : first_unreacheable_pc_(0), pc_offset_(0), label_(NULL), branch_type_(UnknownBranchType) {} BranchInfo(ptrdiff_t offset, Label* label, ImmBranchType branch_type) : pc_offset_(offset), label_(label), branch_type_(branch_type) { first_unreacheable_pc_ = pc_offset_ + Instruction::GetImmBranchForwardRange(branch_type_); } static bool IsValidComparison(const BranchInfo& branch_1, const BranchInfo& branch_2) { // BranchInfo are always compared against against other objects with // the same branch type. if (branch_1.branch_type_ != branch_2.branch_type_) { return false; } // Since we should never have two branch infos with the same offsets, it // first looks like we should check that offsets are different. However // the operators may also be used to *search* for a branch info in the // set. bool same_offsets = (branch_1.pc_offset_ == branch_2.pc_offset_); return (!same_offsets || ((branch_1.label_ == branch_2.label_) && (branch_1.first_unreacheable_pc_ == branch_2.first_unreacheable_pc_))); } // We must provide comparison operators to work with InvalSet. bool operator==(const BranchInfo& other) const { VIXL_ASSERT(IsValidComparison(*this, other)); return pc_offset_ == other.pc_offset_; } bool operator<(const BranchInfo& other) const { VIXL_ASSERT(IsValidComparison(*this, other)); return pc_offset_ < other.pc_offset_; } bool operator<=(const BranchInfo& other) const { VIXL_ASSERT(IsValidComparison(*this, other)); return pc_offset_ <= other.pc_offset_; } bool operator>(const BranchInfo& other) const { VIXL_ASSERT(IsValidComparison(*this, other)); return pc_offset_ > other.pc_offset_; } // First instruction position that is not reachable by the branch using a // positive branch offset. ptrdiff_t first_unreacheable_pc_; // Offset of the branch in the code generation buffer. ptrdiff_t pc_offset_; // The label branched to. Label* label_; ImmBranchType branch_type_; }; bool BranchTypeUsesVeneers(ImmBranchType type) { return (type != UnknownBranchType) && (type != UncondBranchType); } void RegisterUnresolvedBranch(ptrdiff_t branch_pos, Label* label, ImmBranchType branch_type); void DeleteUnresolvedBranchInfoForLabel(Label* label); bool ShouldEmitVeneer(int64_t first_unreacheable_pc, size_t amount); bool ShouldEmitVeneers(size_t amount) { return ShouldEmitVeneer(unresolved_branches_.GetFirstLimit(), amount); } void CheckEmitFor(size_t amount, EmitOption option = kBranchRequired); void Emit(EmitOption option, size_t margin); // The code size generated for a veneer. Currently one branch instruction. // This is for code size checking purposes, and can be extended in the future // for example if we decide to add nops between the veneers. static const int kVeneerCodeSize = 1 * kInstructionSize; // The maximum size of code other than veneers that can be generated when // emitting a veneer pool. Currently there can be an additional branch to jump // over the pool. static const int kPoolNonVeneerCodeSize = 1 * kInstructionSize; void UpdateNextCheckPoint() { SetNextCheckpoint(GetNextCheckPoint()); } int GetNumberOfPotentialVeneers() const { return static_cast(unresolved_branches_.GetSize()); } VIXL_DEPRECATED("GetNumberOfPotentialVeneers", int NumberOfPotentialVeneers() const) { return GetNumberOfPotentialVeneers(); } size_t GetMaxSize() const { return kPoolNonVeneerCodeSize + unresolved_branches_.GetSize() * kVeneerCodeSize; } VIXL_DEPRECATED("GetMaxSize", size_t MaxSize() const) { return GetMaxSize(); } size_t GetOtherPoolsMaxSize() const; VIXL_DEPRECATED("GetOtherPoolsMaxSize", size_t OtherPoolsMaxSize() const) { return GetOtherPoolsMaxSize(); } static const int kNPreallocatedInfos = 4; static const ptrdiff_t kInvalidOffset = PTRDIFF_MAX; static const size_t kReclaimFrom = 128; static const size_t kReclaimFactor = 16; private: typedef InvalSet BranchInfoTypedSetBase; typedef InvalSetIterator BranchInfoTypedSetIterBase; class BranchInfoTypedSet : public BranchInfoTypedSetBase { public: BranchInfoTypedSet() : BranchInfoTypedSetBase() {} ptrdiff_t GetFirstLimit() { if (empty()) { return kInvalidOffset; } return GetMinElementKey(); } VIXL_DEPRECATED("GetFirstLimit", ptrdiff_t FirstLimit()) { return GetFirstLimit(); } }; class BranchInfoTypedSetIterator : public BranchInfoTypedSetIterBase { public: BranchInfoTypedSetIterator() : BranchInfoTypedSetIterBase(NULL) {} explicit BranchInfoTypedSetIterator(BranchInfoTypedSet* typed_set) : BranchInfoTypedSetIterBase(typed_set) {} // TODO: Remove these and use the STL-like interface instead. using BranchInfoTypedSetIterBase::Advance; using BranchInfoTypedSetIterBase::Current; }; class BranchInfoSet { public: void insert(BranchInfo branch_info) { ImmBranchType type = branch_info.branch_type_; VIXL_ASSERT(IsValidBranchType(type)); typed_set_[BranchIndexFromType(type)].insert(branch_info); } void erase(BranchInfo branch_info) { if (IsValidBranchType(branch_info.branch_type_)) { int index = BranchInfoSet::BranchIndexFromType(branch_info.branch_type_); typed_set_[index].erase(branch_info); } } size_t GetSize() const { size_t res = 0; for (int i = 0; i < kNumberOfTrackedBranchTypes; i++) { res += typed_set_[i].size(); } return res; } VIXL_DEPRECATED("GetSize", size_t size() const) { return GetSize(); } bool IsEmpty() const { for (int i = 0; i < kNumberOfTrackedBranchTypes; i++) { if (!typed_set_[i].empty()) { return false; } } return true; } VIXL_DEPRECATED("IsEmpty", bool empty() const) { return IsEmpty(); } ptrdiff_t GetFirstLimit() { ptrdiff_t res = kInvalidOffset; for (int i = 0; i < kNumberOfTrackedBranchTypes; i++) { res = std::min(res, typed_set_[i].GetFirstLimit()); } return res; } VIXL_DEPRECATED("GetFirstLimit", ptrdiff_t FirstLimit()) { return GetFirstLimit(); } void Reset() { for (int i = 0; i < kNumberOfTrackedBranchTypes; i++) { typed_set_[i].clear(); } } static ImmBranchType BranchTypeFromIndex(int index) { switch (index) { case 0: return CondBranchType; case 1: return CompareBranchType; case 2: return TestBranchType; default: VIXL_UNREACHABLE(); return UnknownBranchType; } } static int BranchIndexFromType(ImmBranchType branch_type) { switch (branch_type) { case CondBranchType: return 0; case CompareBranchType: return 1; case TestBranchType: return 2; default: VIXL_UNREACHABLE(); return 0; } } bool IsValidBranchType(ImmBranchType branch_type) { return (branch_type != UnknownBranchType) && (branch_type != UncondBranchType); } private: static const int kNumberOfTrackedBranchTypes = 3; BranchInfoTypedSet typed_set_[kNumberOfTrackedBranchTypes]; friend class VeneerPool; friend class BranchInfoSetIterator; }; class BranchInfoSetIterator { public: explicit BranchInfoSetIterator(BranchInfoSet* set) : set_(set) { for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { new (&sub_iterator_[i]) BranchInfoTypedSetIterator(&(set_->typed_set_[i])); } } VeneerPool::BranchInfo* Current() { for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { if (!sub_iterator_[i].Done()) { return sub_iterator_[i].Current(); } } VIXL_UNREACHABLE(); return NULL; } void Advance() { VIXL_ASSERT(!Done()); for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { if (!sub_iterator_[i].Done()) { sub_iterator_[i].Advance(); return; } } VIXL_UNREACHABLE(); } bool Done() const { for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { if (!sub_iterator_[i].Done()) return false; } return true; } void AdvanceToNextType() { VIXL_ASSERT(!Done()); for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { if (!sub_iterator_[i].Done()) { sub_iterator_[i].Finish(); return; } } VIXL_UNREACHABLE(); } void DeleteCurrentAndAdvance() { for (int i = 0; i < BranchInfoSet::kNumberOfTrackedBranchTypes; i++) { if (!sub_iterator_[i].Done()) { sub_iterator_[i].DeleteCurrentAndAdvance(); return; } } } private: BranchInfoSet* set_; BranchInfoTypedSetIterator sub_iterator_[BranchInfoSet::kNumberOfTrackedBranchTypes]; }; ptrdiff_t GetNextCheckPoint() { if (unresolved_branches_.IsEmpty()) { return kNoCheckpointRequired; } else { return unresolved_branches_.GetFirstLimit(); } } VIXL_DEPRECATED("GetNextCheckPoint", ptrdiff_t NextCheckPoint()) { return GetNextCheckPoint(); } // Information about unresolved (forward) branches. BranchInfoSet unresolved_branches_; }; // Helper for common Emission checks. // The macro-instruction maps to a single instruction. class SingleEmissionCheckScope : public EmissionCheckScope { public: explicit SingleEmissionCheckScope(MacroAssemblerInterface* masm) : EmissionCheckScope(masm, kInstructionSize) {} }; // The macro instruction is a "typical" macro-instruction. Typical macro- // instruction only emit a few instructions, a few being defined as 8 here. class MacroEmissionCheckScope : public EmissionCheckScope { public: explicit MacroEmissionCheckScope(MacroAssemblerInterface* masm) : EmissionCheckScope(masm, kTypicalMacroInstructionMaxSize) {} private: static const size_t kTypicalMacroInstructionMaxSize = 8 * kInstructionSize; }; // This scope simplifies the handling of the SVE `movprfx` instruction. // // If dst.Aliases(src): // - Start an ExactAssemblyScope(masm, kInstructionSize). // Otherwise: // - Start an ExactAssemblyScope(masm, 2 * kInstructionSize). // - Generate a suitable `movprfx` instruction. // // In both cases, the ExactAssemblyScope is left with enough remaining space for // exactly one destructive instruction. class MovprfxHelperScope : public ExactAssemblyScope { public: inline MovprfxHelperScope(MacroAssembler* masm, const ZRegister& dst, const ZRegister& src); inline MovprfxHelperScope(MacroAssembler* masm, const ZRegister& dst, const PRegister& pg, const ZRegister& src); // TODO: Implement constructors that examine _all_ sources. If `dst` aliases // any other source register, we can't use `movprfx`. This isn't obviously // useful, but the MacroAssembler should not generate invalid code for it. // Valid behaviour can be implemented using `mov`. // // The best way to handle this in an instruction-agnostic way is probably to // use variadic templates. private: inline bool ShouldGenerateMovprfx(const ZRegister& dst, const ZRegister& src) { VIXL_ASSERT(AreSameLaneSize(dst, src)); return !dst.Aliases(src); } inline bool ShouldGenerateMovprfx(const ZRegister& dst, const PRegister& pg, const ZRegister& src) { VIXL_ASSERT(pg.IsMerging() || pg.IsZeroing()); // We need to emit movprfx in two cases: // 1. To give a predicated merging unary instruction zeroing predication. // 2. To make destructive instructions constructive. // // There are no predicated zeroing instructions that can take movprfx, so we // will never generate an unnecessary movprfx with this logic. return pg.IsZeroing() || ShouldGenerateMovprfx(dst, src); } }; enum BranchType { // Copies of architectural conditions. // The associated conditions can be used in place of those, the code will // take care of reinterpreting them with the correct type. integer_eq = eq, integer_ne = ne, integer_hs = hs, integer_lo = lo, integer_mi = mi, integer_pl = pl, integer_vs = vs, integer_vc = vc, integer_hi = hi, integer_ls = ls, integer_ge = ge, integer_lt = lt, integer_gt = gt, integer_le = le, integer_al = al, integer_nv = nv, // These two are *different* from the architectural codes al and nv. // 'always' is used to generate unconditional branches. // 'never' is used to not generate a branch (generally as the inverse // branch type of 'always). always, never, // cbz and cbnz reg_zero, reg_not_zero, // tbz and tbnz reg_bit_clear, reg_bit_set, // Aliases. kBranchTypeFirstCondition = eq, kBranchTypeLastCondition = nv, kBranchTypeFirstUsingReg = reg_zero, kBranchTypeFirstUsingBit = reg_bit_clear, // SVE branch conditions. integer_none = eq, integer_any = ne, integer_nlast = cs, integer_last = cc, integer_first = mi, integer_nfrst = pl, integer_pmore = hi, integer_plast = ls, integer_tcont = ge, integer_tstop = lt }; enum DiscardMoveMode { kDontDiscardForSameWReg, kDiscardForSameWReg }; // The macro assembler supports moving automatically pre-shifted immediates for // arithmetic and logical instructions, and then applying a post shift in the // instruction to undo the modification, in order to reduce the code emitted for // an operation. For example: // // Add(x0, x0, 0x1f7de) => movz x16, 0xfbef; add x0, x0, x16, lsl #1. // // This optimisation can be only partially applied when the stack pointer is an // operand or destination, so this enumeration is used to control the shift. enum PreShiftImmMode { kNoShift, // Don't pre-shift. kLimitShiftForSP, // Limit pre-shift for add/sub extend use. kAnyShift // Allow any pre-shift. }; enum FPMacroNaNPropagationOption { // The default option. This generates a run-time error in macros that respect // this option. NoFPMacroNaNPropagationSelected, // For example, Fmin(result, NaN(a), NaN(b)) always selects NaN(a) if both // NaN(a) and NaN(b) are both quiet, or both are signalling, at the // cost of extra code generation in some cases. StrictNaNPropagation, // For example, Fmin(result, NaN(a), NaN(b)) selects either NaN, but using the // fewest instructions. FastNaNPropagation }; class MacroAssembler : public Assembler, public MacroAssemblerInterface { public: explicit MacroAssembler( PositionIndependentCodeOption pic = PositionIndependentCode); MacroAssembler(size_t capacity, PositionIndependentCodeOption pic = PositionIndependentCode); MacroAssembler(byte* buffer, size_t capacity, PositionIndependentCodeOption pic = PositionIndependentCode); ~MacroAssembler(); enum FinalizeOption { kFallThrough, // There may be more code to execute after calling Finalize. kUnreachable // Anything generated after calling Finalize is unreachable. }; virtual vixl::internal::AssemblerBase* AsAssemblerBase() VIXL_OVERRIDE { return this; } // TODO(pools): implement these functions. virtual void EmitPoolHeader() VIXL_OVERRIDE {} virtual void EmitPoolFooter() VIXL_OVERRIDE {} virtual void EmitPaddingBytes(int n) VIXL_OVERRIDE { USE(n); } virtual void EmitNopBytes(int n) VIXL_OVERRIDE { USE(n); } // Start generating code from the beginning of the buffer, discarding any code // and data that has already been emitted into the buffer. // // In order to avoid any accidental transfer of state, Reset ASSERTs that the // constant pool is not blocked. void Reset(); // Finalize a code buffer of generated instructions. This function must be // called before executing or copying code from the buffer. By default, // anything generated after this should not be reachable (the last instruction // generated is an unconditional branch). If you need to generate more code, // then set `option` to kFallThrough. void FinalizeCode(FinalizeOption option = kUnreachable); // Constant generation helpers. // These functions return the number of instructions required to move the // immediate into the destination register. Also, if the masm pointer is // non-null, it generates the code to do so. // The two features are implemented using one function to avoid duplication of // the logic. // The function can be used to evaluate the cost of synthesizing an // instruction using 'mov immediate' instructions. A user might prefer loading // a constant using the literal pool instead of using multiple 'mov immediate' // instructions. static int MoveImmediateHelper(MacroAssembler* masm, const Register& rd, uint64_t imm); // Logical macros. void And(const Register& rd, const Register& rn, const Operand& operand); void Ands(const Register& rd, const Register& rn, const Operand& operand); void Bic(const Register& rd, const Register& rn, const Operand& operand); void Bics(const Register& rd, const Register& rn, const Operand& operand); void Orr(const Register& rd, const Register& rn, const Operand& operand); void Orn(const Register& rd, const Register& rn, const Operand& operand); void Eor(const Register& rd, const Register& rn, const Operand& operand); void Eon(const Register& rd, const Register& rn, const Operand& operand); void Tst(const Register& rn, const Operand& operand); void LogicalMacro(const Register& rd, const Register& rn, const Operand& operand, LogicalOp op); // Add and sub macros. void Add(const Register& rd, const Register& rn, const Operand& operand, FlagsUpdate S = LeaveFlags); void Adds(const Register& rd, const Register& rn, const Operand& operand); void Sub(const Register& rd, const Register& rn, const Operand& operand, FlagsUpdate S = LeaveFlags); void Subs(const Register& rd, const Register& rn, const Operand& operand); void Cmn(const Register& rn, const Operand& operand); void Cmp(const Register& rn, const Operand& operand); void Neg(const Register& rd, const Operand& operand); void Negs(const Register& rd, const Operand& operand); void AddSubMacro(const Register& rd, const Register& rn, const Operand& operand, FlagsUpdate S, AddSubOp op); // Add/sub with carry macros. void Adc(const Register& rd, const Register& rn, const Operand& operand); void Adcs(const Register& rd, const Register& rn, const Operand& operand); void Sbc(const Register& rd, const Register& rn, const Operand& operand); void Sbcs(const Register& rd, const Register& rn, const Operand& operand); void Ngc(const Register& rd, const Operand& operand); void Ngcs(const Register& rd, const Operand& operand); void AddSubWithCarryMacro(const Register& rd, const Register& rn, const Operand& operand, FlagsUpdate S, AddSubWithCarryOp op); void Rmif(const Register& xn, unsigned shift, StatusFlags flags); void Setf8(const Register& wn); void Setf16(const Register& wn); // Move macros. void Mov(const Register& rd, uint64_t imm); void Mov(const Register& rd, const Operand& operand, DiscardMoveMode discard_mode = kDontDiscardForSameWReg); void Mvn(const Register& rd, uint64_t imm) { Mov(rd, (rd.GetSizeInBits() == kXRegSize) ? ~imm : (~imm & kWRegMask)); } void Mvn(const Register& rd, const Operand& operand); // Try to move an immediate into the destination register in a single // instruction. Returns true for success, and updates the contents of dst. // Returns false, otherwise. bool TryOneInstrMoveImmediate(const Register& dst, uint64_t imm); // Move an immediate into register dst, and return an Operand object for // use with a subsequent instruction that accepts a shift. The value moved // into dst is not necessarily equal to imm; it may have had a shifting // operation applied to it that will be subsequently undone by the shift // applied in the Operand. Operand MoveImmediateForShiftedOp(const Register& dst, uint64_t imm, PreShiftImmMode mode); void Move(const GenericOperand& dst, const GenericOperand& src); // Synthesises the address represented by a MemOperand into a register. void ComputeAddress(const Register& dst, const MemOperand& mem_op); // Conditional macros. void Ccmp(const Register& rn, const Operand& operand, StatusFlags nzcv, Condition cond); void Ccmn(const Register& rn, const Operand& operand, StatusFlags nzcv, Condition cond); void ConditionalCompareMacro(const Register& rn, const Operand& operand, StatusFlags nzcv, Condition cond, ConditionalCompareOp op); // On return, the boolean values pointed to will indicate whether `left` and // `right` should be synthesised in a temporary register. static void GetCselSynthesisInformation(const Register& rd, const Operand& left, const Operand& right, bool* should_synthesise_left, bool* should_synthesise_right) { // Note that the helper does not need to look at the condition. CselHelper(NULL, rd, left, right, eq, should_synthesise_left, should_synthesise_right); } void Csel(const Register& rd, const Operand& left, const Operand& right, Condition cond) { CselHelper(this, rd, left, right, cond); } // Load/store macros. #define DECLARE_FUNCTION(FN, REGTYPE, REG, OP) \ void FN(const REGTYPE REG, const MemOperand& addr); LS_MACRO_LIST(DECLARE_FUNCTION) #undef DECLARE_FUNCTION void LoadStoreMacro(const CPURegister& rt, const MemOperand& addr, LoadStoreOp op); #define DECLARE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \ void FN(const REGTYPE REG, const REGTYPE REG2, const MemOperand& addr); LSPAIR_MACRO_LIST(DECLARE_FUNCTION) #undef DECLARE_FUNCTION void LoadStorePairMacro(const CPURegister& rt, const CPURegister& rt2, const MemOperand& addr, LoadStorePairOp op); void Prfm(PrefetchOperation op, const MemOperand& addr); // Push or pop up to 4 registers of the same width to or from the stack, // using the current stack pointer as set by SetStackPointer. // // If an argument register is 'NoReg', all further arguments are also assumed // to be 'NoReg', and are thus not pushed or popped. // // Arguments are ordered such that "Push(a, b);" is functionally equivalent // to "Push(a); Push(b);". // // It is valid to push the same register more than once, and there is no // restriction on the order in which registers are specified. // // It is not valid to pop into the same register more than once in one // operation, not even into the zero register. // // If the current stack pointer (as set by SetStackPointer) is sp, then it // must be aligned to 16 bytes on entry and the total size of the specified // registers must also be a multiple of 16 bytes. // // Even if the current stack pointer is not the system stack pointer (sp), // Push (and derived methods) will still modify the system stack pointer in // order to comply with ABI rules about accessing memory below the system // stack pointer. // // Other than the registers passed into Pop, the stack pointer and (possibly) // the system stack pointer, these methods do not modify any other registers. void Push(const CPURegister& src0, const CPURegister& src1 = NoReg, const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg); void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg, const CPURegister& dst2 = NoReg, const CPURegister& dst3 = NoReg); // Alternative forms of Push and Pop, taking a RegList or CPURegList that // specifies the registers that are to be pushed or popped. Higher-numbered // registers are associated with higher memory addresses (as in the A32 push // and pop instructions). // // (Push|Pop)SizeRegList allow you to specify the register size as a // parameter. Only kXRegSize, kWRegSize, kDRegSize and kSRegSize are // supported. // // Otherwise, (Push|Pop)(CPU|X|W|D|S)RegList is preferred. void PushCPURegList(CPURegList registers); void PopCPURegList(CPURegList registers); void PushSizeRegList( RegList registers, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { PushCPURegList(CPURegList(type, reg_size, registers)); } void PopSizeRegList(RegList registers, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { PopCPURegList(CPURegList(type, reg_size, registers)); } void PushXRegList(RegList regs) { PushSizeRegList(regs, kXRegSize); } void PopXRegList(RegList regs) { PopSizeRegList(regs, kXRegSize); } void PushWRegList(RegList regs) { PushSizeRegList(regs, kWRegSize); } void PopWRegList(RegList regs) { PopSizeRegList(regs, kWRegSize); } void PushDRegList(RegList regs) { PushSizeRegList(regs, kDRegSize, CPURegister::kVRegister); } void PopDRegList(RegList regs) { PopSizeRegList(regs, kDRegSize, CPURegister::kVRegister); } void PushSRegList(RegList regs) { PushSizeRegList(regs, kSRegSize, CPURegister::kVRegister); } void PopSRegList(RegList regs) { PopSizeRegList(regs, kSRegSize, CPURegister::kVRegister); } // Push the specified register 'count' times. void PushMultipleTimes(int count, Register src); // Poke 'src' onto the stack. The offset is in bytes. // // If the current stack pointer (as set by SetStackPointer) is sp, then sp // must be aligned to 16 bytes. void Poke(const Register& src, const Operand& offset); // Peek at a value on the stack, and put it in 'dst'. The offset is in bytes. // // If the current stack pointer (as set by SetStackPointer) is sp, then sp // must be aligned to 16 bytes. void Peek(const Register& dst, const Operand& offset); // Alternative forms of Peek and Poke, taking a RegList or CPURegList that // specifies the registers that are to be pushed or popped. Higher-numbered // registers are associated with higher memory addresses. // // (Peek|Poke)SizeRegList allow you to specify the register size as a // parameter. Only kXRegSize, kWRegSize, kDRegSize and kSRegSize are // supported. // // Otherwise, (Peek|Poke)(CPU|X|W|D|S)RegList is preferred. void PeekCPURegList(CPURegList registers, int64_t offset) { LoadCPURegList(registers, MemOperand(StackPointer(), offset)); } void PokeCPURegList(CPURegList registers, int64_t offset) { StoreCPURegList(registers, MemOperand(StackPointer(), offset)); } void PeekSizeRegList( RegList registers, int64_t offset, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { PeekCPURegList(CPURegList(type, reg_size, registers), offset); } void PokeSizeRegList( RegList registers, int64_t offset, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { PokeCPURegList(CPURegList(type, reg_size, registers), offset); } void PeekXRegList(RegList regs, int64_t offset) { PeekSizeRegList(regs, offset, kXRegSize); } void PokeXRegList(RegList regs, int64_t offset) { PokeSizeRegList(regs, offset, kXRegSize); } void PeekWRegList(RegList regs, int64_t offset) { PeekSizeRegList(regs, offset, kWRegSize); } void PokeWRegList(RegList regs, int64_t offset) { PokeSizeRegList(regs, offset, kWRegSize); } void PeekDRegList(RegList regs, int64_t offset) { PeekSizeRegList(regs, offset, kDRegSize, CPURegister::kVRegister); } void PokeDRegList(RegList regs, int64_t offset) { PokeSizeRegList(regs, offset, kDRegSize, CPURegister::kVRegister); } void PeekSRegList(RegList regs, int64_t offset) { PeekSizeRegList(regs, offset, kSRegSize, CPURegister::kVRegister); } void PokeSRegList(RegList regs, int64_t offset) { PokeSizeRegList(regs, offset, kSRegSize, CPURegister::kVRegister); } // Claim or drop stack space without actually accessing memory. // // If the current stack pointer (as set by SetStackPointer) is sp, then it // must be aligned to 16 bytes and the size claimed or dropped must be a // multiple of 16 bytes. void Claim(const Operand& size); void Drop(const Operand& size); // As above, but for multiples of the SVE vector length. void ClaimVL(int64_t multiplier) { // We never need to worry about sp alignment because the VL is always a // multiple of 16. VIXL_STATIC_ASSERT((kZRegMinSizeInBytes % 16) == 0); VIXL_ASSERT(multiplier >= 0); Addvl(sp, sp, -multiplier); } void DropVL(int64_t multiplier) { VIXL_STATIC_ASSERT((kZRegMinSizeInBytes % 16) == 0); VIXL_ASSERT(multiplier >= 0); Addvl(sp, sp, multiplier); } // Preserve the callee-saved registers (as defined by AAPCS64). // // Higher-numbered registers are pushed before lower-numbered registers, and // thus get higher addresses. // Floating-point registers are pushed before general-purpose registers, and // thus get higher addresses. // // This method must not be called unless StackPointer() is sp, and it is // aligned to 16 bytes. void PushCalleeSavedRegisters(); // Restore the callee-saved registers (as defined by AAPCS64). // // Higher-numbered registers are popped after lower-numbered registers, and // thus come from higher addresses. // Floating-point registers are popped after general-purpose registers, and // thus come from higher addresses. // // This method must not be called unless StackPointer() is sp, and it is // aligned to 16 bytes. void PopCalleeSavedRegisters(); void LoadCPURegList(CPURegList registers, const MemOperand& src); void StoreCPURegList(CPURegList registers, const MemOperand& dst); // Remaining instructions are simple pass-through calls to the assembler. void Adr(const Register& rd, Label* label) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); adr(rd, label); } void Adrp(const Register& rd, Label* label) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); adrp(rd, label); } void Asr(const Register& rd, const Register& rn, unsigned shift) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); asr(rd, rn, shift); } void Asr(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); asrv(rd, rn, rm); } // Branch type inversion relies on these relations. VIXL_STATIC_ASSERT((reg_zero == (reg_not_zero ^ 1)) && (reg_bit_clear == (reg_bit_set ^ 1)) && (always == (never ^ 1))); BranchType InvertBranchType(BranchType type) { if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) { return static_cast( InvertCondition(static_cast(type))); } else { return static_cast(type ^ 1); } } void B(Label* label, BranchType type, Register reg = NoReg, int bit = -1); void B(Label* label); void B(Label* label, Condition cond); void B(Condition cond, Label* label) { B(label, cond); } void Bfm(const Register& rd, const Register& rn, unsigned immr, unsigned imms) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); bfm(rd, rn, immr, imms); } void Bfi(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); bfi(rd, rn, lsb, width); } void Bfc(const Register& rd, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); bfc(rd, lsb, width); } void Bfxil(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); bfxil(rd, rn, lsb, width); } void Bind(Label* label, BranchTargetIdentifier id = EmitBTI_none); // Bind a label to a specified offset from the start of the buffer. void BindToOffset(Label* label, ptrdiff_t offset); void Bl(Label* label) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bl(label); } void Blr(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!xn.IsZero()); SingleEmissionCheckScope guard(this); blr(xn); } void Br(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!xn.IsZero()); SingleEmissionCheckScope guard(this); br(xn); } void Braaz(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); braaz(xn); } void Brabz(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brabz(xn); } void Blraaz(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); blraaz(xn); } void Blrabz(const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); blrabz(xn); } void Retaa() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); retaa(); } void Retab() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); retab(); } void Braa(const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); braa(xn, xm); } void Brab(const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brab(xn, xm); } void Blraa(const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); blraa(xn, xm); } void Blrab(const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); blrab(xn, xm); } void Brk(int code = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brk(code); } void Cbnz(const Register& rt, Label* label); void Cbz(const Register& rt, Label* label); void Cinc(const Register& rd, const Register& rn, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); cinc(rd, rn, cond); } void Cinv(const Register& rd, const Register& rn, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); cinv(rd, rn, cond); } #define PAUTH_SYSTEM_MODES(V) \ V(az) \ V(bz) \ V(asp) \ V(bsp) #define DEFINE_MACRO_ASM_FUNCS(SUFFIX) \ void Paci##SUFFIX() { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ paci##SUFFIX(); \ } \ void Auti##SUFFIX() { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ auti##SUFFIX(); \ } PAUTH_SYSTEM_MODES(DEFINE_MACRO_ASM_FUNCS) #undef DEFINE_MACRO_ASM_FUNCS // The 1716 pac and aut instructions encourage people to use x16 and x17 // directly, perhaps without realising that this is forbidden. For example: // // UseScratchRegisterScope temps(&masm); // Register temp = temps.AcquireX(); // temp will be x16 // __ Mov(x17, ptr); // __ Mov(x16, modifier); // Will override temp! // __ Pacia1716(); // // To work around this issue, you must exclude x16 and x17 from the scratch // register list. You may need to replace them with other registers: // // UseScratchRegisterScope temps(&masm); // temps.Exclude(x16, x17); // temps.Include(x10, x11); // __ Mov(x17, ptr); // __ Mov(x16, modifier); // __ Pacia1716(); void Pacia1716() { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x16)); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x17)); SingleEmissionCheckScope guard(this); pacia1716(); } void Pacib1716() { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x16)); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x17)); SingleEmissionCheckScope guard(this); pacib1716(); } void Autia1716() { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x16)); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x17)); SingleEmissionCheckScope guard(this); autia1716(); } void Autib1716() { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x16)); VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(x17)); SingleEmissionCheckScope guard(this); autib1716(); } void Xpaclri() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); xpaclri(); } void Clrex() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clrex(); } void Cls(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); cls(rd, rn); } void Clz(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); clz(rd, rn); } void Cneg(const Register& rd, const Register& rn, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); cneg(rd, rn, cond); } void Esb() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); esb(); } void Csdb() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); csdb(); } void Cset(const Register& rd, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); cset(rd, cond); } void Csetm(const Register& rd, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); csetm(rd, cond); } void Csinc(const Register& rd, const Register& rn, const Register& rm, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT((cond != al) && (cond != nv)); SingleEmissionCheckScope guard(this); csinc(rd, rn, rm, cond); } void Csinv(const Register& rd, const Register& rn, const Register& rm, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT((cond != al) && (cond != nv)); SingleEmissionCheckScope guard(this); csinv(rd, rn, rm, cond); } void Csneg(const Register& rd, const Register& rn, const Register& rm, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT((cond != al) && (cond != nv)); SingleEmissionCheckScope guard(this); csneg(rd, rn, rm, cond); } void Dmb(BarrierDomain domain, BarrierType type) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dmb(domain, type); } void Dsb(BarrierDomain domain, BarrierType type) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dsb(domain, type); } void Extr(const Register& rd, const Register& rn, const Register& rm, unsigned lsb) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); extr(rd, rn, rm, lsb); } void Fadd(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fadd(vd, vn, vm); } void Fccmp(const VRegister& vn, const VRegister& vm, StatusFlags nzcv, Condition cond, FPTrapFlags trap = DisableTrap) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT((cond != al) && (cond != nv)); SingleEmissionCheckScope guard(this); FPCCompareMacro(vn, vm, nzcv, cond, trap); } void Fccmpe(const VRegister& vn, const VRegister& vm, StatusFlags nzcv, Condition cond) { Fccmp(vn, vm, nzcv, cond, EnableTrap); } void Fcmp(const VRegister& vn, const VRegister& vm, FPTrapFlags trap = DisableTrap) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); FPCompareMacro(vn, vm, trap); } void Fcmp(const VRegister& vn, double value, FPTrapFlags trap = DisableTrap); void Fcmpe(const VRegister& vn, double value); void Fcmpe(const VRegister& vn, const VRegister& vm) { Fcmp(vn, vm, EnableTrap); } void Fcsel(const VRegister& vd, const VRegister& vn, const VRegister& vm, Condition cond) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT((cond != al) && (cond != nv)); SingleEmissionCheckScope guard(this); fcsel(vd, vn, vm, cond); } void Fcvt(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvt(vd, vn); } void Fcvtl(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtl(vd, vn); } void Fcvtl2(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtl2(vd, vn); } void Fcvtn(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtn(vd, vn); } void Fcvtn2(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtn2(vd, vn); } void Fcvtxn(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtxn(vd, vn); } void Fcvtxn2(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtxn2(vd, vn); } void Fcvtas(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtas(rd, vn); } void Fcvtau(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtau(rd, vn); } void Fcvtms(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtms(rd, vn); } void Fcvtmu(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtmu(rd, vn); } void Fcvtns(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtns(rd, vn); } void Fcvtnu(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtnu(rd, vn); } void Fcvtps(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtps(rd, vn); } void Fcvtpu(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtpu(rd, vn); } void Fcvtzs(const Register& rd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtzs(rd, vn, fbits); } void Fjcvtzs(const Register& rd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fjcvtzs(rd, vn); } void Fcvtzu(const Register& rd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fcvtzu(rd, vn, fbits); } void Fdiv(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fdiv(vd, vn, vm); } void Fmax(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmax(vd, vn, vm); } void Fmaxnm(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmaxnm(vd, vn, vm); } void Fmin(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmin(vd, vn, vm); } void Fminnm(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fminnm(vd, vn, vm); } void Fmov(const VRegister& vd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); // TODO: Use DiscardMoveMode to allow this move to be elided if vd.Is(vn). fmov(vd, vn); } void Fmov(const VRegister& vd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); fmov(vd, rn); } void Fmov(const VRegister& vd, int index, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (vd.Is1D() && (index == 0)) { mov(vd, index, rn); } else { fmov(vd, index, rn); } } void Fmov(const Register& rd, const VRegister& vn, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (vn.Is1D() && (index == 0)) { mov(rd, vn, index); } else { fmov(rd, vn, index); } } // Provide explicit double and float interfaces for FP immediate moves, rather // than relying on implicit C++ casts. This allows signalling NaNs to be // preserved when the immediate matches the format of vd. Most systems convert // signalling NaNs to quiet NaNs when converting between float and double. void Fmov(VRegister vd, double imm); void Fmov(VRegister vd, float imm); void Fmov(VRegister vd, const Float16 imm); // Provide a template to allow other types to be converted automatically. template void Fmov(VRegister vd, T imm) { VIXL_ASSERT(allow_macro_instructions_); Fmov(vd, static_cast(imm)); } void Fmov(Register rd, VRegister vn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); fmov(rd, vn); } void Fmul(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmul(vd, vn, vm); } void Fnmul(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fnmul(vd, vn, vm); } void Fmadd(const VRegister& vd, const VRegister& vn, const VRegister& vm, const VRegister& va) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmadd(vd, vn, vm, va); } void Fmsub(const VRegister& vd, const VRegister& vn, const VRegister& vm, const VRegister& va) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmsub(vd, vn, vm, va); } void Fnmadd(const VRegister& vd, const VRegister& vn, const VRegister& vm, const VRegister& va) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fnmadd(vd, vn, vm, va); } void Fnmsub(const VRegister& vd, const VRegister& vn, const VRegister& vm, const VRegister& va) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fnmsub(vd, vn, vm, va); } void Fsub(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fsub(vd, vn, vm); } void Hint(SystemHint code) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); hint(code); } void Hint(int imm7) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); hint(imm7); } void Hlt(int code) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); hlt(code); } void Isb() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); isb(); } void Ldar(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldar(rt, src); } void Ldarb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldarb(rt, src); } void Ldarh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldarh(rt, src); } void Ldlar(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldlar(rt, src); } void Ldlarb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldlarb(rt, src); } void Ldlarh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldlarh(rt, src); } void Ldaxp(const Register& rt, const Register& rt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.Aliases(rt2)); SingleEmissionCheckScope guard(this); ldaxp(rt, rt2, src); } void Ldaxr(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldaxr(rt, src); } void Ldaxrb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldaxrb(rt, src); } void Ldaxrh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldaxrh(rt, src); } // clang-format off #define COMPARE_AND_SWAP_SINGLE_MACRO_LIST(V) \ V(cas, Cas) \ V(casa, Casa) \ V(casl, Casl) \ V(casal, Casal) \ V(casb, Casb) \ V(casab, Casab) \ V(caslb, Caslb) \ V(casalb, Casalb) \ V(cash, Cash) \ V(casah, Casah) \ V(caslh, Caslh) \ V(casalh, Casalh) // clang-format on #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const Register& rs, const Register& rt, const MemOperand& src) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(rs, rt, src); \ } COMPARE_AND_SWAP_SINGLE_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // clang-format off #define COMPARE_AND_SWAP_PAIR_MACRO_LIST(V) \ V(casp, Casp) \ V(caspa, Caspa) \ V(caspl, Caspl) \ V(caspal, Caspal) // clang-format on #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const Register& rs, \ const Register& rs2, \ const Register& rt, \ const Register& rt2, \ const MemOperand& src) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(rs, rs2, rt, rt2, src); \ } COMPARE_AND_SWAP_PAIR_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // These macros generate all the variations of the atomic memory operations, // e.g. ldadd, ldadda, ldaddb, staddl, etc. // clang-format off #define ATOMIC_MEMORY_SIMPLE_MACRO_LIST(V, DEF, MASM_PRE, ASM_PRE) \ V(DEF, MASM_PRE##add, ASM_PRE##add) \ V(DEF, MASM_PRE##clr, ASM_PRE##clr) \ V(DEF, MASM_PRE##eor, ASM_PRE##eor) \ V(DEF, MASM_PRE##set, ASM_PRE##set) \ V(DEF, MASM_PRE##smax, ASM_PRE##smax) \ V(DEF, MASM_PRE##smin, ASM_PRE##smin) \ V(DEF, MASM_PRE##umax, ASM_PRE##umax) \ V(DEF, MASM_PRE##umin, ASM_PRE##umin) #define ATOMIC_MEMORY_STORE_MACRO_MODES(V, MASM, ASM) \ V(MASM, ASM) \ V(MASM##l, ASM##l) \ V(MASM##b, ASM##b) \ V(MASM##lb, ASM##lb) \ V(MASM##h, ASM##h) \ V(MASM##lh, ASM##lh) #define ATOMIC_MEMORY_LOAD_MACRO_MODES(V, MASM, ASM) \ ATOMIC_MEMORY_STORE_MACRO_MODES(V, MASM, ASM) \ V(MASM##a, ASM##a) \ V(MASM##al, ASM##al) \ V(MASM##ab, ASM##ab) \ V(MASM##alb, ASM##alb) \ V(MASM##ah, ASM##ah) \ V(MASM##alh, ASM##alh) // clang-format on #define DEFINE_MACRO_LOAD_ASM_FUNC(MASM, ASM) \ void MASM(const Register& rs, const Register& rt, const MemOperand& src) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(rs, rt, src); \ } #define DEFINE_MACRO_STORE_ASM_FUNC(MASM, ASM) \ void MASM(const Register& rs, const MemOperand& src) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(rs, src); \ } ATOMIC_MEMORY_SIMPLE_MACRO_LIST(ATOMIC_MEMORY_LOAD_MACRO_MODES, DEFINE_MACRO_LOAD_ASM_FUNC, Ld, ld) ATOMIC_MEMORY_SIMPLE_MACRO_LIST(ATOMIC_MEMORY_STORE_MACRO_MODES, DEFINE_MACRO_STORE_ASM_FUNC, St, st) #define DEFINE_MACRO_SWP_ASM_FUNC(MASM, ASM) \ void MASM(const Register& rs, const Register& rt, const MemOperand& src) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(rs, rt, src); \ } ATOMIC_MEMORY_LOAD_MACRO_MODES(DEFINE_MACRO_SWP_ASM_FUNC, Swp, swp) #undef DEFINE_MACRO_LOAD_ASM_FUNC #undef DEFINE_MACRO_STORE_ASM_FUNC #undef DEFINE_MACRO_SWP_ASM_FUNC void Ldaprb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(src.IsImmediateOffset()); if (src.GetOffset() == 0) { ldaprb(rt, src); } else { ldapurb(rt, src); } } void Ldapursb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldapursb(rt, src); } void Ldaprh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(src.IsImmediateOffset()); if (src.GetOffset() == 0) { ldaprh(rt, src); } else { ldapurh(rt, src); } } void Ldapursh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldapursh(rt, src); } void Ldapr(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(src.IsImmediateOffset()); if (src.GetOffset() == 0) { ldapr(rt, src); } else { ldapur(rt, src); } } void Ldapursw(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldapursw(rt, src); } void Ldnp(const CPURegister& rt, const CPURegister& rt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnp(rt, rt2, src); } // Provide both double and float interfaces for FP immediate loads, rather // than relying on implicit C++ casts. This allows signalling NaNs to be // preserved when the immediate matches the format of fd. Most systems convert // signalling NaNs to quiet NaNs when converting between float and double. void Ldr(const VRegister& vt, double imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); RawLiteral* literal; if (vt.IsD()) { literal = new Literal(imm, &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } else { literal = new Literal(static_cast(imm), &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } ldr(vt, literal); } void Ldr(const VRegister& vt, float imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); RawLiteral* literal; if (vt.IsS()) { literal = new Literal(imm, &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } else { literal = new Literal(static_cast(imm), &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } ldr(vt, literal); } void Ldr(const VRegister& vt, uint64_t high64, uint64_t low64) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(vt.IsQ()); SingleEmissionCheckScope guard(this); ldr(vt, new Literal(high64, low64, &literal_pool_, RawLiteral::kDeletedOnPlacementByPool)); } void Ldr(const Register& rt, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.IsZero()); SingleEmissionCheckScope guard(this); RawLiteral* literal; if (rt.Is64Bits()) { literal = new Literal(imm, &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } else { VIXL_ASSERT(rt.Is32Bits()); VIXL_ASSERT(IsUint32(imm) || IsInt32(imm)); literal = new Literal(static_cast(imm), &literal_pool_, RawLiteral::kDeletedOnPlacementByPool); } ldr(rt, literal); } void Ldrsw(const Register& rt, uint32_t imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.IsZero()); SingleEmissionCheckScope guard(this); ldrsw(rt, new Literal(imm, &literal_pool_, RawLiteral::kDeletedOnPlacementByPool)); } void Ldr(const CPURegister& rt, RawLiteral* literal) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldr(rt, literal); } void Ldrsw(const Register& rt, RawLiteral* literal) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldrsw(rt, literal); } void Ldxp(const Register& rt, const Register& rt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.Aliases(rt2)); SingleEmissionCheckScope guard(this); ldxp(rt, rt2, src); } void Ldxr(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldxr(rt, src); } void Ldxrb(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldxrb(rt, src); } void Ldxrh(const Register& rt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldxrh(rt, src); } void Lsl(const Register& rd, const Register& rn, unsigned shift) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); lsl(rd, rn, shift); } void Lsl(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); lslv(rd, rn, rm); } void Lsr(const Register& rd, const Register& rn, unsigned shift) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); lsr(rd, rn, shift); } void Lsr(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); lsrv(rd, rn, rm); } void Ldraa(const Register& xt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldraa(xt, src); } void Ldrab(const Register& xt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldrab(xt, src); } void Madd(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); madd(rd, rn, rm, ra); } void Mneg(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); mneg(rd, rn, rm); } void Mov(const Register& rd, const Register& rn, DiscardMoveMode discard_mode = kDontDiscardForSameWReg) { VIXL_ASSERT(allow_macro_instructions_); // Emit a register move only if the registers are distinct, or if they are // not X registers. // // Note that mov(w0, w0) is not a no-op because it clears the top word of // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W // registers is not required to clear the top word of the X register. In // this case, the instruction is discarded. // // If the sp is an operand, add #0 is emitted, otherwise, orr #0. if (!rd.Is(rn) || (rd.Is32Bits() && (discard_mode == kDontDiscardForSameWReg))) { SingleEmissionCheckScope guard(this); mov(rd, rn); } } void Movk(const Register& rd, uint64_t imm, int shift = -1) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); SingleEmissionCheckScope guard(this); movk(rd, imm, shift); } void Mrs(const Register& rt, SystemRegister sysreg) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.IsZero()); SingleEmissionCheckScope guard(this); mrs(rt, sysreg); } void Msr(SystemRegister sysreg, const Register& rt) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rt.IsZero()); SingleEmissionCheckScope guard(this); msr(sysreg, rt); } void Cfinv() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cfinv(); } void Axflag() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); axflag(); } void Xaflag() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); xaflag(); } void Sys(int op1, int crn, int crm, int op2, const Register& rt = xzr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sys(op1, crn, crm, op2, rt); } void Dc(DataCacheOp op, const Register& rt) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dc(op, rt); } void Ic(InstructionCacheOp op, const Register& rt) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ic(op, rt); } void Msub(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); msub(rd, rn, rm, ra); } void Mul(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); mul(rd, rn, rm); } void Nop() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nop(); } void Rbit(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); rbit(rd, rn); } void Ret(const Register& xn = lr) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!xn.IsZero()); SingleEmissionCheckScope guard(this); ret(xn); } void Rev(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); rev(rd, rn); } void Rev16(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); rev16(rd, rn); } void Rev32(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); rev32(rd, rn); } void Rev64(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); rev64(rd, rn); } #define PAUTH_MASM_VARIATIONS(V) \ V(Paci, paci) \ V(Pacd, pacd) \ V(Auti, auti) \ V(Autd, autd) #define DEFINE_MACRO_ASM_FUNCS(MASM_PRE, ASM_PRE) \ void MASM_PRE##a(const Register& xd, const Register& xn) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM_PRE##a(xd, xn); \ } \ void MASM_PRE##za(const Register& xd) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM_PRE##za(xd); \ } \ void MASM_PRE##b(const Register& xd, const Register& xn) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM_PRE##b(xd, xn); \ } \ void MASM_PRE##zb(const Register& xd) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM_PRE##zb(xd); \ } PAUTH_MASM_VARIATIONS(DEFINE_MACRO_ASM_FUNCS) #undef DEFINE_MACRO_ASM_FUNCS void Pacga(const Register& xd, const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); pacga(xd, xn, xm); } void Xpaci(const Register& xd) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); xpaci(xd); } void Xpacd(const Register& xd) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); xpacd(xd); } void Ror(const Register& rd, const Register& rs, unsigned shift) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rs.IsZero()); SingleEmissionCheckScope guard(this); ror(rd, rs, shift); } void Ror(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); rorv(rd, rn, rm); } void Sbfiz(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sbfiz(rd, rn, lsb, width); } void Sbfm(const Register& rd, const Register& rn, unsigned immr, unsigned imms) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sbfm(rd, rn, immr, imms); } void Sbfx(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sbfx(rd, rn, lsb, width); } void Scvtf(const VRegister& vd, const Register& rn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); scvtf(vd, rn, fbits); } void Sdiv(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); sdiv(rd, rn, rm); } void Smaddl(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); smaddl(rd, rn, rm, ra); } void Smsubl(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); smsubl(rd, rn, rm, ra); } void Smull(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); smull(rd, rn, rm); } void Smulh(const Register& xd, const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!xd.IsZero()); VIXL_ASSERT(!xn.IsZero()); VIXL_ASSERT(!xm.IsZero()); SingleEmissionCheckScope guard(this); smulh(xd, xn, xm); } void Stlr(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(dst.IsImmediateOffset()); if (dst.GetOffset() == 0) { stlr(rt, dst); } else { stlur(rt, dst); } } void Stlrb(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(dst.IsImmediateOffset()); if (dst.GetOffset() == 0) { stlrb(rt, dst); } else { stlurb(rt, dst); } } void Stlrh(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); VIXL_ASSERT(dst.IsImmediateOffset()); if (dst.GetOffset() == 0) { stlrh(rt, dst); } else { stlurh(rt, dst); } } void Stllr(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); stllr(rt, dst); } void Stllrb(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); stllrb(rt, dst); } void Stllrh(const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); stllrh(rt, dst); } void Stlxp(const Register& rs, const Register& rt, const Register& rt2, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); VIXL_ASSERT(!rs.Aliases(rt2)); SingleEmissionCheckScope guard(this); stlxp(rs, rt, rt2, dst); } void Stlxr(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stlxr(rs, rt, dst); } void Stlxrb(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stlxrb(rs, rt, dst); } void Stlxrh(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stlxrh(rs, rt, dst); } void Stnp(const CPURegister& rt, const CPURegister& rt2, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); stnp(rt, rt2, dst); } void Stxp(const Register& rs, const Register& rt, const Register& rt2, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); VIXL_ASSERT(!rs.Aliases(rt2)); SingleEmissionCheckScope guard(this); stxp(rs, rt, rt2, dst); } void Stxr(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stxr(rs, rt, dst); } void Stxrb(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stxrb(rs, rt, dst); } void Stxrh(const Register& rs, const Register& rt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rs.Aliases(dst.GetBaseRegister())); VIXL_ASSERT(!rs.Aliases(rt)); SingleEmissionCheckScope guard(this); stxrh(rs, rt, dst); } void Svc(int code) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); svc(code); } void Sxtb(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sxtb(rd, rn); } void Sxth(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sxth(rd, rn); } void Sxtw(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); sxtw(rd, rn); } void Tbl(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(vd, vn, vm); } void Tbl(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(vd, vn, vn2, vm); } void Tbl(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vn3, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(vd, vn, vn2, vn3, vm); } void Tbl(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vn3, const VRegister& vn4, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(vd, vn, vn2, vn3, vn4, vm); } void Tbx(const VRegister& vd, const VRegister& vn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbx(vd, vn, vm); } void Tbx(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbx(vd, vn, vn2, vm); } void Tbx(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vn3, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbx(vd, vn, vn2, vn3, vm); } void Tbx(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vn3, const VRegister& vn4, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbx(vd, vn, vn2, vn3, vn4, vm); } void Tbnz(const Register& rt, unsigned bit_pos, Label* label); void Tbz(const Register& rt, unsigned bit_pos, Label* label); void Ubfiz(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); ubfiz(rd, rn, lsb, width); } void Ubfm(const Register& rd, const Register& rn, unsigned immr, unsigned imms) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); ubfm(rd, rn, immr, imms); } void Ubfx(const Register& rd, const Register& rn, unsigned lsb, unsigned width) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); ubfx(rd, rn, lsb, width); } void Ucvtf(const VRegister& vd, const Register& rn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); ucvtf(vd, rn, fbits); } void Udiv(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); udiv(rd, rn, rm); } void Umaddl(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); umaddl(rd, rn, rm, ra); } void Umull(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); SingleEmissionCheckScope guard(this); umull(rd, rn, rm); } void Umulh(const Register& xd, const Register& xn, const Register& xm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!xd.IsZero()); VIXL_ASSERT(!xn.IsZero()); VIXL_ASSERT(!xm.IsZero()); SingleEmissionCheckScope guard(this); umulh(xd, xn, xm); } void Umsubl(const Register& rd, const Register& rn, const Register& rm, const Register& ra) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); VIXL_ASSERT(!rm.IsZero()); VIXL_ASSERT(!ra.IsZero()); SingleEmissionCheckScope guard(this); umsubl(rd, rn, rm, ra); } void Unreachable() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (generate_simulator_code_) { hlt(kUnreachableOpcode); } else { // Use the architecturally-defined UDF instruction to abort on hardware, // because using HLT and BRK tends to make the process difficult to debug. udf(kUnreachableOpcode); } } void Uxtb(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); uxtb(rd, rn); } void Uxth(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); uxth(rd, rn); } void Uxtw(const Register& rd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(!rd.IsZero()); VIXL_ASSERT(!rn.IsZero()); SingleEmissionCheckScope guard(this); uxtw(rd, rn); } // NEON 3 vector register instructions. #define NEON_3VREG_MACRO_LIST(V) \ V(add, Add) \ V(addhn, Addhn) \ V(addhn2, Addhn2) \ V(addp, Addp) \ V(and_, And) \ V(bic, Bic) \ V(bif, Bif) \ V(bit, Bit) \ V(bsl, Bsl) \ V(cmeq, Cmeq) \ V(cmge, Cmge) \ V(cmgt, Cmgt) \ V(cmhi, Cmhi) \ V(cmhs, Cmhs) \ V(cmtst, Cmtst) \ V(eor, Eor) \ V(fabd, Fabd) \ V(facge, Facge) \ V(facgt, Facgt) \ V(faddp, Faddp) \ V(fcmeq, Fcmeq) \ V(fcmge, Fcmge) \ V(fcmgt, Fcmgt) \ V(fmaxnmp, Fmaxnmp) \ V(fmaxp, Fmaxp) \ V(fminnmp, Fminnmp) \ V(fminp, Fminp) \ V(fmla, Fmla) \ V(fmlal, Fmlal) \ V(fmlal2, Fmlal2) \ V(fmls, Fmls) \ V(fmlsl, Fmlsl) \ V(fmlsl2, Fmlsl2) \ V(fmulx, Fmulx) \ V(frecps, Frecps) \ V(frsqrts, Frsqrts) \ V(mla, Mla) \ V(mls, Mls) \ V(mul, Mul) \ V(orn, Orn) \ V(orr, Orr) \ V(pmul, Pmul) \ V(pmull, Pmull) \ V(pmull2, Pmull2) \ V(raddhn, Raddhn) \ V(raddhn2, Raddhn2) \ V(rsubhn, Rsubhn) \ V(rsubhn2, Rsubhn2) \ V(saba, Saba) \ V(sabal, Sabal) \ V(sabal2, Sabal2) \ V(sabd, Sabd) \ V(sabdl, Sabdl) \ V(sabdl2, Sabdl2) \ V(saddl, Saddl) \ V(saddl2, Saddl2) \ V(saddw, Saddw) \ V(saddw2, Saddw2) \ V(shadd, Shadd) \ V(shsub, Shsub) \ V(smax, Smax) \ V(smaxp, Smaxp) \ V(smin, Smin) \ V(sminp, Sminp) \ V(smlal, Smlal) \ V(smlal2, Smlal2) \ V(smlsl, Smlsl) \ V(smlsl2, Smlsl2) \ V(smull, Smull) \ V(smull2, Smull2) \ V(sqadd, Sqadd) \ V(sqdmlal, Sqdmlal) \ V(sqdmlal2, Sqdmlal2) \ V(sqdmlsl, Sqdmlsl) \ V(sqdmlsl2, Sqdmlsl2) \ V(sqdmulh, Sqdmulh) \ V(sqdmull, Sqdmull) \ V(sqdmull2, Sqdmull2) \ V(sqrdmulh, Sqrdmulh) \ V(sdot, Sdot) \ V(sqrdmlah, Sqrdmlah) \ V(udot, Udot) \ V(sqrdmlsh, Sqrdmlsh) \ V(sqrshl, Sqrshl) \ V(sqshl, Sqshl) \ V(sqsub, Sqsub) \ V(srhadd, Srhadd) \ V(srshl, Srshl) \ V(sshl, Sshl) \ V(ssubl, Ssubl) \ V(ssubl2, Ssubl2) \ V(ssubw, Ssubw) \ V(ssubw2, Ssubw2) \ V(sub, Sub) \ V(subhn, Subhn) \ V(subhn2, Subhn2) \ V(trn1, Trn1) \ V(trn2, Trn2) \ V(uaba, Uaba) \ V(uabal, Uabal) \ V(uabal2, Uabal2) \ V(uabd, Uabd) \ V(uabdl, Uabdl) \ V(uabdl2, Uabdl2) \ V(uaddl, Uaddl) \ V(uaddl2, Uaddl2) \ V(uaddw, Uaddw) \ V(uaddw2, Uaddw2) \ V(uhadd, Uhadd) \ V(uhsub, Uhsub) \ V(umax, Umax) \ V(umaxp, Umaxp) \ V(umin, Umin) \ V(uminp, Uminp) \ V(umlal, Umlal) \ V(umlal2, Umlal2) \ V(umlsl, Umlsl) \ V(umlsl2, Umlsl2) \ V(umull, Umull) \ V(umull2, Umull2) \ V(uqadd, Uqadd) \ V(uqrshl, Uqrshl) \ V(uqshl, Uqshl) \ V(uqsub, Uqsub) \ V(urhadd, Urhadd) \ V(urshl, Urshl) \ V(ushl, Ushl) \ V(usubl, Usubl) \ V(usubl2, Usubl2) \ V(usubw, Usubw) \ V(usubw2, Usubw2) \ V(uzp1, Uzp1) \ V(uzp2, Uzp2) \ V(zip1, Zip1) \ V(zip2, Zip2) \ V(smmla, Smmla) \ V(ummla, Ummla) \ V(usmmla, Usmmla) \ V(usdot, Usdot) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const VRegister& vd, const VRegister& vn, const VRegister& vm) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(vd, vn, vm); \ } NEON_3VREG_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // NEON 2 vector register instructions. #define NEON_2VREG_MACRO_LIST(V) \ V(abs, Abs) \ V(addp, Addp) \ V(addv, Addv) \ V(cls, Cls) \ V(clz, Clz) \ V(cnt, Cnt) \ V(fabs, Fabs) \ V(faddp, Faddp) \ V(fcvtas, Fcvtas) \ V(fcvtau, Fcvtau) \ V(fcvtms, Fcvtms) \ V(fcvtmu, Fcvtmu) \ V(fcvtns, Fcvtns) \ V(fcvtnu, Fcvtnu) \ V(fcvtps, Fcvtps) \ V(fcvtpu, Fcvtpu) \ V(fmaxnmp, Fmaxnmp) \ V(fmaxnmv, Fmaxnmv) \ V(fmaxp, Fmaxp) \ V(fmaxv, Fmaxv) \ V(fminnmp, Fminnmp) \ V(fminnmv, Fminnmv) \ V(fminp, Fminp) \ V(fminv, Fminv) \ V(fneg, Fneg) \ V(frecpe, Frecpe) \ V(frecpx, Frecpx) \ V(frint32x, Frint32x) \ V(frint32z, Frint32z) \ V(frint64x, Frint64x) \ V(frint64z, Frint64z) \ V(frinta, Frinta) \ V(frinti, Frinti) \ V(frintm, Frintm) \ V(frintn, Frintn) \ V(frintp, Frintp) \ V(frintx, Frintx) \ V(frintz, Frintz) \ V(frsqrte, Frsqrte) \ V(fsqrt, Fsqrt) \ V(mov, Mov) \ V(mvn, Mvn) \ V(neg, Neg) \ V(not_, Not) \ V(rbit, Rbit) \ V(rev16, Rev16) \ V(rev32, Rev32) \ V(rev64, Rev64) \ V(sadalp, Sadalp) \ V(saddlp, Saddlp) \ V(saddlv, Saddlv) \ V(smaxv, Smaxv) \ V(sminv, Sminv) \ V(sqabs, Sqabs) \ V(sqneg, Sqneg) \ V(sqxtn, Sqxtn) \ V(sqxtn2, Sqxtn2) \ V(sqxtun, Sqxtun) \ V(sqxtun2, Sqxtun2) \ V(suqadd, Suqadd) \ V(sxtl, Sxtl) \ V(sxtl2, Sxtl2) \ V(uadalp, Uadalp) \ V(uaddlp, Uaddlp) \ V(uaddlv, Uaddlv) \ V(umaxv, Umaxv) \ V(uminv, Uminv) \ V(uqxtn, Uqxtn) \ V(uqxtn2, Uqxtn2) \ V(urecpe, Urecpe) \ V(ursqrte, Ursqrte) \ V(usqadd, Usqadd) \ V(uxtl, Uxtl) \ V(uxtl2, Uxtl2) \ V(xtn, Xtn) \ V(xtn2, Xtn2) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const VRegister& vd, const VRegister& vn) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(vd, vn); \ } NEON_2VREG_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // NEON 2 vector register with immediate instructions. #define NEON_2VREG_FPIMM_MACRO_LIST(V) \ V(fcmeq, Fcmeq) \ V(fcmge, Fcmge) \ V(fcmgt, Fcmgt) \ V(fcmle, Fcmle) \ V(fcmlt, Fcmlt) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const VRegister& vd, const VRegister& vn, double imm) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(vd, vn, imm); \ } NEON_2VREG_FPIMM_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // NEON by element instructions. #define NEON_BYELEMENT_MACRO_LIST(V) \ V(fmul, Fmul) \ V(fmla, Fmla) \ V(fmlal, Fmlal) \ V(fmlal2, Fmlal2) \ V(fmls, Fmls) \ V(fmlsl, Fmlsl) \ V(fmlsl2, Fmlsl2) \ V(fmulx, Fmulx) \ V(mul, Mul) \ V(mla, Mla) \ V(mls, Mls) \ V(sqdmulh, Sqdmulh) \ V(sqrdmulh, Sqrdmulh) \ V(sdot, Sdot) \ V(sqrdmlah, Sqrdmlah) \ V(udot, Udot) \ V(sqrdmlsh, Sqrdmlsh) \ V(sqdmull, Sqdmull) \ V(sqdmull2, Sqdmull2) \ V(sqdmlal, Sqdmlal) \ V(sqdmlal2, Sqdmlal2) \ V(sqdmlsl, Sqdmlsl) \ V(sqdmlsl2, Sqdmlsl2) \ V(smull, Smull) \ V(smull2, Smull2) \ V(smlal, Smlal) \ V(smlal2, Smlal2) \ V(smlsl, Smlsl) \ V(smlsl2, Smlsl2) \ V(umull, Umull) \ V(umull2, Umull2) \ V(umlal, Umlal) \ V(umlal2, Umlal2) \ V(umlsl, Umlsl) \ V(umlsl2, Umlsl2) \ V(sudot, Sudot) \ V(usdot, Usdot) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const VRegister& vd, \ const VRegister& vn, \ const VRegister& vm, \ int vm_index) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(vd, vn, vm, vm_index); \ } NEON_BYELEMENT_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC #define NEON_2VREG_SHIFT_MACRO_LIST(V) \ V(rshrn, Rshrn) \ V(rshrn2, Rshrn2) \ V(shl, Shl) \ V(shll, Shll) \ V(shll2, Shll2) \ V(shrn, Shrn) \ V(shrn2, Shrn2) \ V(sli, Sli) \ V(sqrshrn, Sqrshrn) \ V(sqrshrn2, Sqrshrn2) \ V(sqrshrun, Sqrshrun) \ V(sqrshrun2, Sqrshrun2) \ V(sqshl, Sqshl) \ V(sqshlu, Sqshlu) \ V(sqshrn, Sqshrn) \ V(sqshrn2, Sqshrn2) \ V(sqshrun, Sqshrun) \ V(sqshrun2, Sqshrun2) \ V(sri, Sri) \ V(srshr, Srshr) \ V(srsra, Srsra) \ V(sshr, Sshr) \ V(ssra, Ssra) \ V(uqrshrn, Uqrshrn) \ V(uqrshrn2, Uqrshrn2) \ V(uqshl, Uqshl) \ V(uqshrn, Uqshrn) \ V(uqshrn2, Uqshrn2) \ V(urshr, Urshr) \ V(ursra, Ursra) \ V(ushr, Ushr) \ V(usra, Usra) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const VRegister& vd, const VRegister& vn, int shift) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ ASM(vd, vn, shift); \ } NEON_2VREG_SHIFT_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC #define NEON_2VREG_SHIFT_LONG_MACRO_LIST(V) \ V(shll, sshll, Sshll) \ V(shll, ushll, Ushll) \ V(shll2, sshll2, Sshll2) \ V(shll2, ushll2, Ushll2) #define DEFINE_MACRO_ASM_FUNC(ASM1, ASM2, MASM) \ void MASM(const VRegister& vd, const VRegister& vn, int shift) { \ VIXL_ASSERT(allow_macro_instructions_); \ SingleEmissionCheckScope guard(this); \ if (vn.GetLaneSizeInBits() == static_cast(shift)) { \ ASM1(vd, vn, shift); \ } else { \ ASM2(vd, vn, shift); \ } \ } NEON_2VREG_SHIFT_LONG_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC // SVE 3 vector register instructions. #define SVE_3VREG_COMMUTATIVE_MACRO_LIST(V) \ V(add, Add) \ V(and_, And) \ V(bic, Bic) \ V(eor, Eor) \ V(mul, Mul) \ V(orr, Orr) \ V(sabd, Sabd) \ V(shadd, Shadd) \ V(smax, Smax) \ V(smin, Smin) \ V(smulh, Smulh) \ V(sqadd, Sqadd) \ V(srhadd, Srhadd) \ V(uabd, Uabd) \ V(uhadd, Uhadd) \ V(umax, Umax) \ V(umin, Umin) \ V(umulh, Umulh) \ V(uqadd, Uqadd) \ V(urhadd, Urhadd) #define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \ void MASM(const ZRegister& zd, \ const PRegisterM& pg, \ const ZRegister& zn, \ const ZRegister& zm) { \ VIXL_ASSERT(allow_macro_instructions_); \ if (zd.Aliases(zn)) { \ SingleEmissionCheckScope guard(this); \ ASM(zd, pg, zd, zm); \ } else if (zd.Aliases(zm)) { \ SingleEmissionCheckScope guard(this); \ ASM(zd, pg, zd, zn); \ } else { \ MovprfxHelperScope guard(this, zd, pg, zn); \ ASM(zd, pg, zd, zm); \ } \ } SVE_3VREG_COMMUTATIVE_MACRO_LIST(DEFINE_MACRO_ASM_FUNC) #undef DEFINE_MACRO_ASM_FUNC void Bic(const VRegister& vd, const int imm8, const int left_shift = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bic(vd, imm8, left_shift); } void Cmeq(const VRegister& vd, const VRegister& vn, int imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmeq(vd, vn, imm); } void Cmge(const VRegister& vd, const VRegister& vn, int imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmge(vd, vn, imm); } void Cmgt(const VRegister& vd, const VRegister& vn, int imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmgt(vd, vn, imm); } void Cmle(const VRegister& vd, const VRegister& vn, int imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmle(vd, vn, imm); } void Cmlt(const VRegister& vd, const VRegister& vn, int imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmlt(vd, vn, imm); } void Dup(const VRegister& vd, const VRegister& vn, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dup(vd, vn, index); } void Dup(const VRegister& vd, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dup(vd, rn); } void Ext(const VRegister& vd, const VRegister& vn, const VRegister& vm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ext(vd, vn, vm, index); } void Fcadd(const VRegister& vd, const VRegister& vn, const VRegister& vm, int rot) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcadd(vd, vn, vm, rot); } void Fcmla(const VRegister& vd, const VRegister& vn, const VRegister& vm, int vm_index, int rot) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmla(vd, vn, vm, vm_index, rot); } void Fcmla(const VRegister& vd, const VRegister& vn, const VRegister& vm, int rot) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmla(vd, vn, vm, rot); } void Ins(const VRegister& vd, int vd_index, const VRegister& vn, int vn_index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ins(vd, vd_index, vn, vn_index); } void Ins(const VRegister& vd, int vd_index, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ins(vd, vd_index, rn); } void Ld1(const VRegister& vt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1(vt, src); } void Ld1(const VRegister& vt, const VRegister& vt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1(vt, vt2, src); } void Ld1(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1(vt, vt2, vt3, src); } void Ld1(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1(vt, vt2, vt3, vt4, src); } void Ld1(const VRegister& vt, int lane, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1(vt, lane, src); } void Ld1r(const VRegister& vt, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld1r(vt, src); } void Ld2(const VRegister& vt, const VRegister& vt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2(vt, vt2, src); } void Ld2(const VRegister& vt, const VRegister& vt2, int lane, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2(vt, vt2, lane, src); } void Ld2r(const VRegister& vt, const VRegister& vt2, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2r(vt, vt2, src); } void Ld3(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3(vt, vt2, vt3, src); } void Ld3(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, int lane, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3(vt, vt2, vt3, lane, src); } void Ld3r(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3r(vt, vt2, vt3, src); } void Ld4(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4(vt, vt2, vt3, vt4, src); } void Ld4(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, int lane, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4(vt, vt2, vt3, vt4, lane, src); } void Ld4r(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, const MemOperand& src) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4r(vt, vt2, vt3, vt4, src); } void Mov(const VRegister& vd, int vd_index, const VRegister& vn, int vn_index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(vd, vd_index, vn, vn_index); } void Mov(const VRegister& vd, const VRegister& vn, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(vd, vn, index); } void Mov(const VRegister& vd, int vd_index, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(vd, vd_index, rn); } void Mov(const Register& rd, const VRegister& vn, int vn_index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(rd, vn, vn_index); } void Movi(const VRegister& vd, uint64_t imm, Shift shift = LSL, int shift_amount = 0); void Movi(const VRegister& vd, uint64_t hi, uint64_t lo); void Mvni(const VRegister& vd, const int imm8, Shift shift = LSL, const int shift_amount = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mvni(vd, imm8, shift, shift_amount); } void Orr(const VRegister& vd, const int imm8, const int left_shift = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orr(vd, imm8, left_shift); } void Scvtf(const VRegister& vd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); scvtf(vd, vn, fbits); } void Ucvtf(const VRegister& vd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ucvtf(vd, vn, fbits); } void Fcvtzs(const VRegister& vd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtzs(vd, vn, fbits); } void Fcvtzu(const VRegister& vd, const VRegister& vn, int fbits = 0) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtzu(vd, vn, fbits); } void St1(const VRegister& vt, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st1(vt, dst); } void St1(const VRegister& vt, const VRegister& vt2, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st1(vt, vt2, dst); } void St1(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st1(vt, vt2, vt3, dst); } void St1(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st1(vt, vt2, vt3, vt4, dst); } void St1(const VRegister& vt, int lane, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st1(vt, lane, dst); } void St2(const VRegister& vt, const VRegister& vt2, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2(vt, vt2, dst); } void St3(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3(vt, vt2, vt3, dst); } void St4(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4(vt, vt2, vt3, vt4, dst); } void St2(const VRegister& vt, const VRegister& vt2, int lane, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2(vt, vt2, lane, dst); } void St3(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, int lane, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3(vt, vt2, vt3, lane, dst); } void St4(const VRegister& vt, const VRegister& vt2, const VRegister& vt3, const VRegister& vt4, int lane, const MemOperand& dst) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4(vt, vt2, vt3, vt4, lane, dst); } void Smov(const Register& rd, const VRegister& vn, int vn_index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smov(rd, vn, vn_index); } void Umov(const Register& rd, const VRegister& vn, int vn_index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umov(rd, vn, vn_index); } void Crc32b(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32b(rd, rn, rm); } void Crc32h(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32h(rd, rn, rm); } void Crc32w(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32w(rd, rn, rm); } void Crc32x(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32x(rd, rn, rm); } void Crc32cb(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32cb(rd, rn, rm); } void Crc32ch(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32ch(rd, rn, rm); } void Crc32cw(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32cw(rd, rn, rm); } void Crc32cx(const Register& rd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); crc32cx(rd, rn, rm); } // Scalable Vector Extensions. void Abs(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); abs(zd, pg, zn); } void Add(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); add(zd, zn, zm); } void Add(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); AddSubHelper(kAddImmediate, zd, zn, imm); } void Addpl(const Register& xd, const Register& xn, int64_t multiplier); void Addvl(const Register& xd, const Register& xn, int64_t multiplier); // Note that unlike the core ISA, SVE's `adr` is not PC-relative. void Adr(const ZRegister& zd, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); adr(zd, addr); } void And(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); and_(pd, pg, pn, pm); } void And(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { and_(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void And(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameLaneSize(zd, zn, zm)); SingleEmissionCheckScope guard(this); and_(zd.VnD(), zn.VnD(), zm.VnD()); } void Ands(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ands(pd, pg, pn, pm); } void Andv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); andv(vd, pg, zn); } void Asr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); asr(zd, pg, zd, shift); } void Asr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Asr(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); asr(zd, zn, shift); } void Asr(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); asr(zd, zn, zm); } void Asrd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); asrd(zd, pg, zd, shift); } void Bic(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bic(pd, pg, pn, pm); } void Bic(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameLaneSize(zd, zn, zm)); SingleEmissionCheckScope guard(this); bic(zd.VnD(), zn.VnD(), zm.VnD()); } void Bic(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { bic(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void Bics(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bics(pd, pg, pn, pm); } void Brka(const PRegisterWithLaneSize& pd, const PRegister& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brka(pd, pg, pn); } void Brkas(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkas(pd, pg, pn); } void Brkb(const PRegisterWithLaneSize& pd, const PRegister& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkb(pd, pg, pn); } void Brkbs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkbs(pd, pg, pn); } void Brkn(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); if (!pd.Aliases(pm)) { Mov(pd, pm); } SingleEmissionCheckScope guard(this); brkn(pd, pg, pn, pd); } void Brkns(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); if (!pd.Aliases(pm)) { Mov(pd, pm); } SingleEmissionCheckScope guard(this); brkns(pd, pg, pn, pd); } void Brkpa(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkpa(pd, pg, pn, pm); } void Brkpas(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkpas(pd, pg, pn, pm); } void Brkpb(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkpb(pd, pg, pn, pm); } void Brkpbs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); brkpbs(pd, pg, pn, pm); } void Clasta(const Register& rd, const PRegister& pg, const Register& rn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clasta(rd, pg, rn, zm); } void Clasta(const VRegister& vd, const PRegister& pg, const VRegister& vn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clasta(vd, pg, vn, zm); } void Clasta(const ZRegister& zd, const PRegister& pg, const ZRegister& zn, const ZRegister& zm); void Clastb(const Register& rd, const PRegister& pg, const Register& rn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clastb(rd, pg, rn, zm); } void Clastb(const VRegister& vd, const PRegister& pg, const VRegister& vn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clastb(vd, pg, vn, zm); } void Clastb(const ZRegister& zd, const PRegister& pg, const ZRegister& zn, const ZRegister& zm); void Cls(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cls(zd, pg, zn); } void Clz(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); clz(zd, pg, zn); } void Cmpeq(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmpeq(pd, pg, zn, zm); } void Cmpeq(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmpeq(pd, pg, zn, imm5); } else { CompareHelper(eq, pd, pg, zn, imm); } } void Cmpge(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmpge(pd, pg, zn, zm); } void Cmpge(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmpge(pd, pg, zn, imm5); } else { CompareHelper(ge, pd, pg, zn, imm); } } void Cmpgt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmpgt(pd, pg, zn, zm); } void Cmpgt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmpgt(pd, pg, zn, imm5); } else { CompareHelper(gt, pd, pg, zn, imm); } } void Cmphi(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmphi(pd, pg, zn, zm); } void Cmphi(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); if (imm.IsUintN(7)) { SingleEmissionCheckScope guard(this); cmphi(pd, pg, zn, static_cast(imm.AsUintN(7))); } else { CompareHelper(hi, pd, pg, zn, imm); } } void Cmphs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmphs(pd, pg, zn, zm); } void Cmphs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { if (imm.IsUintN(7)) { SingleEmissionCheckScope guard(this); cmphs(pd, pg, zn, static_cast(imm.AsUintN(7))); } else { CompareHelper(hs, pd, pg, zn, imm); } } void Cmple(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmple(pd, pg, zn, zm); } void Cmple(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmple(pd, pg, zn, imm5); } else { CompareHelper(le, pd, pg, zn, imm); } } void Cmplo(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmplo(pd, pg, zn, zm); } void Cmplo(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { if (imm.IsUintN(7)) { SingleEmissionCheckScope guard(this); cmplo(pd, pg, zn, static_cast(imm.AsUintN(7))); } else { CompareHelper(lo, pd, pg, zn, imm); } } void Cmpls(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmpls(pd, pg, zn, zm); } void Cmpls(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { if (imm.IsUintN(7)) { SingleEmissionCheckScope guard(this); cmpls(pd, pg, zn, static_cast(imm.AsUintN(7))); } else { CompareHelper(ls, pd, pg, zn, imm); } } void Cmplt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmplt(pd, pg, zn, zm); } void Cmplt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmplt(pd, pg, zn, imm5); } else { CompareHelper(lt, pd, pg, zn, imm); } } void Cmpne(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cmpne(pd, pg, zn, zm); } void Cmpne(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); int imm5; if (imm.TryEncodeAsIntNForLane<5>(zn, &imm5)) { SingleEmissionCheckScope guard(this); cmpne(pd, pg, zn, imm5); } else { CompareHelper(ne, pd, pg, zn, imm); } } void Cnot(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cnot(zd, pg, zn); } void Cnt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cnt(zd, pg, zn); } void Cntb(const Register& rd, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cntb(rd, pattern, multiplier); } void Cntd(const Register& rd, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cntd(rd, pattern, multiplier); } void Cnth(const Register& rd, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cnth(rd, pattern, multiplier); } void Cntp(const Register& rd, const PRegister& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); // The `cntp` instruction architecturally takes an X register, but the // result will always be in the range [0, kPRegMaxSize] (and therefore // always fits in a W register), so we can accept a W-sized rd here. cntp(rd.X(), pg, pn); } void Cntw(const Register& rd, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cntw(rd, pattern, multiplier); } void Compact(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); compact(zd, pg, zn); } void Cpy(const ZRegister& zd, const PRegister& pg, IntegerOperand imm); void Cpy(const ZRegister& zd, const PRegisterM& pg, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cpy(zd, pg, rn); } void Cpy(const ZRegister& zd, const PRegisterM& pg, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); cpy(zd, pg, vn); } void Ctermeq(const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ctermeq(rn, rm); } void Ctermne(const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ctermne(rn, rm); } void Decb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decb(rdn, pattern, multiplier); } void Decd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decd(rdn, pattern, multiplier); } void Decd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decd(zdn, pattern, multiplier); } void Dech(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dech(rdn, pattern, multiplier); } void Dech(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dech(zdn, pattern, multiplier); } void Decp(const Register& rdn, const PRegisterWithLaneSize& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decp(rdn, pg); } void Decp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `decp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); decp(zd, pg); } void Decp(const ZRegister& zdn, const PRegister& pg) { Decp(zdn, pg, zdn); } void Decw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decw(rdn, pattern, multiplier); } void Decw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); decw(zdn, pattern, multiplier); } void Dup(const ZRegister& zd, const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dup(zd, xn); } void Dup(const ZRegister& zd, const ZRegister& zn, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); dup(zd, zn, index); } void Dup(const ZRegister& zd, IntegerOperand imm); void Eon(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { eon(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void Eor(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); eor(pd, pg, pn, pm); } void Eor(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { eor(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void Eor(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameLaneSize(zd, zn, zm)); SingleEmissionCheckScope guard(this); eor(zd.VnD(), zn.VnD(), zm.VnD()); } void Eors(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); eors(pd, pg, pn, pm); } void Eorv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); eorv(vd, pg, zn); } void Ext(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, unsigned offset) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ext(zd, zn, zm, offset); } void Fabd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fabs(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fabs(zd, pg, zn); } void Facge(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); facge(pd, pg, zn, zm); } void Facgt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); facgt(pd, pg, zn, zm); } void Facle(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); facge(pd, pg, zm, zn); } void Faclt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); facgt(pd, pg, zm, zn); } void Fadd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fadd(zd, pg, zd, imm); } void Fadd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fadd(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fadd(zd, zn, zm); } void Fadda(const VRegister& vd, const PRegister& pg, const VRegister& vn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fadda(vd, pg, vn, zm); } void Faddv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); faddv(vd, pg, zn); } void Fcadd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, int rot); void Fcmeq(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmeq(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmeq(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmeq(pd, pg, zn, zm); } void Fcmge(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmge(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmge(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmge(pd, pg, zn, zm); } void Fcmgt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmgt(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmgt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmgt(pd, pg, zn, zm); } void Fcmla(const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int rot); void Fcmla(const ZRegister& zda, const ZRegister& zn, const ZRegister& zm, int index, int rot) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmla(zda, zn, zm, index, rot); } void Fcmle(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmle(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmle(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmge(pd, pg, zm, zn); } void Fcmlt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmlt(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmlt(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmgt(pd, pg, zm, zn); } void Fcmne(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, double zero) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (zero == 0.0) { fcmne(pd, pg, zn, zero); } else { // TODO: Synthesise other immediates. VIXL_UNIMPLEMENTED(); } } void Fcmne(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmne(pd, pg, zn, zm); } void Fcmuo(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcmuo(pd, pg, zn, zm); } void Fcpy(const ZRegister& zd, const PRegisterM& pg, double imm); void Fcpy(const ZRegister& zd, const PRegisterM& pg, float imm); void Fcpy(const ZRegister& zd, const PRegisterM& pg, Float16 imm); void Fcvt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvt(zd, pg, zn); } void Fcvt(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); // The element type in this predicated movprfx is determined by the larger // type between the source and destination. int lane_size = std::max(zd.GetLaneSizeInBits(), zn.GetLaneSizeInBits()); MovprfxHelperScope guard(this, zd.WithLaneSize(lane_size), pg, zn.WithLaneSize(lane_size)); fcvt(zd, pg.Merging(), zn); } void Fcvtzs(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtzs(zd, pg, zn); } void Fcvtzu(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtzu(zd, pg, zn); } void Fdiv(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fdup(const ZRegister& zd, double imm); void Fdup(const ZRegister& zd, float imm); void Fdup(const ZRegister& zd, Float16 imm); void Fexpa(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fexpa(zd, zn); } void Fmad(const ZRegister& zdn, const PRegisterM& pg, const ZRegister& zm, const ZRegister& za) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmad(zdn, pg, zm, za); } void Fmax(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fmax(zd, pg, zd, imm); } void Fmax( const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Fmaxnm(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fmaxnm(zd, pg, zd, imm); } void Fmaxnm(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fmaxnmv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmaxnmv(vd, pg, zn); } void Fmaxv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmaxv(vd, pg, zn); } void Fmin(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fmin(zd, pg, zd, imm); } void Fmin( const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Fminnm(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fminnm(zd, pg, zd, imm); } void Fminnm(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fminnmv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fminnmv(vd, pg, zn); } void Fminv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fminv(vd, pg, zn); } // zd = za + (zn * zm) void Fmla( const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Fmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); // zd = za - (zn * zm) void Fmls( const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Fmls(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Fmov(const ZRegister& zd, double imm) { VIXL_ASSERT(allow_macro_instructions_); Fdup(zd, imm); } void Fmov(const ZRegister& zd, float imm) { VIXL_ASSERT(allow_macro_instructions_); Fdup(zd, imm); } void Fmov(const ZRegister& zd, Float16 imm) { VIXL_ASSERT(allow_macro_instructions_); Fdup(zd, imm); } void Fmov(const ZRegister& zd, const PRegisterM& pg, double imm) { VIXL_ASSERT(allow_macro_instructions_); Fcpy(zd, pg, imm); } void Fmov(const ZRegister& zd, const PRegisterM& pg, float imm) { VIXL_ASSERT(allow_macro_instructions_); Fcpy(zd, pg, imm); } void Fmov(const ZRegister& zd, const PRegisterM& pg, Float16 imm) { VIXL_ASSERT(allow_macro_instructions_); Fcpy(zd, pg, imm); } void Fmsb(const ZRegister& zdn, const PRegisterM& pg, const ZRegister& zm, const ZRegister& za) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmsb(zdn, pg, zm, za); } void Fmul(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fmul(zd, pg, zd, imm); } void Fmul(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fmul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, unsigned index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmul(zd, zn, zm, index); } void Fmul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fmul(zd, zn, zm); } void Fmulx(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option); void Fneg(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fneg(zd, pg, zn); } void Fnmla( const ZRegister& zda, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Fnmls( const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, FPMacroNaNPropagationOption nan_option = NoFPMacroNaNPropagationSelected); void Frecpe(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frecpe(zd, zn); } void Frecps(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frecps(zd, zn, zm); } void Frecpx(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frecpx(zd, pg, zn); } void Frecpx(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frecpx(zd, pg.Merging(), zn); } void Frinta(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frinta(zd, pg, zn); } void Frinta(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frinta(zd, pg.Merging(), zn); } void Frinti(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frinti(zd, pg, zn); } void Frinti(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frinti(zd, pg.Merging(), zn); } void Frintm(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frintm(zd, pg, zn); } void Frintm(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frintm(zd, pg.Merging(), zn); } void Frintn(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frintn(zd, pg, zn); } void Frintn(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frintn(zd, pg.Merging(), zn); } void Frintp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frintp(zd, pg, zn); } void Frintp(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frintp(zd, pg.Merging(), zn); } void Frintx(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frintx(zd, pg, zn); } void Frintx(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frintx(zd, pg.Merging(), zn); } void Frintz(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frintz(zd, pg, zn); } void Frintz(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); frintz(zd, pg.Merging(), zn); } void Frsqrte(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frsqrte(zd, zn); } void Frsqrts(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); frsqrts(zd, zn, zm); } void Fscale(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fsqrt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fsqrt(zd, pg, zn); } void Fsqrt(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fsqrt(zd, pg.Merging(), zn); } void Fsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, double imm) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fsub(zd, pg, zd, imm); } void Fsub(const ZRegister& zd, const PRegisterM& pg, double imm, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); fsubr(zd, pg, zd, imm); } void Fsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fsub(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fsub(zd, zn, zm); } void Ftmad(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int imm3); void Ftsmul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ftsmul(zd, zn, zm); } void Ftssel(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ftssel(zd, zn, zm); } void Incb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incb(rdn, pattern, multiplier); } void Incd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incd(rdn, pattern, multiplier); } void Incd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incd(zdn, pattern, multiplier); } void Inch(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); inch(rdn, pattern, multiplier); } void Inch(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); inch(zdn, pattern, multiplier); } void Incp(const Register& rdn, const PRegisterWithLaneSize& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incp(rdn, pg); } void Incp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `incp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); incp(zd, pg); } void Incp(const ZRegister& zdn, const PRegister& pg) { Incp(zdn, pg, zdn); } void Incw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incw(rdn, pattern, multiplier); } void Incw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); incw(zdn, pattern, multiplier); } void Index(const ZRegister& zd, const Operand& start, const Operand& step); void Insr(const ZRegister& zdn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); insr(zdn, rm); } void Insr(const ZRegister& zdn, const VRegister& vm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); insr(zdn, vm); } void Insr(const ZRegister& zdn, IntegerOperand imm); void Lasta(const Register& rd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lasta(rd, pg, zn); } void Lasta(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lasta(vd, pg, zn); } void Lastb(const Register& rd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lastb(rd, pg, zn); } void Lastb(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lastb(vd, pg, zn); } void Ld1b(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1h(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1w(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1d(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rb, kBRegSizeInBytes); } void Ld1rh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rh, kHRegSizeInBytes); } void Ld1rw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rw, kSRegSizeInBytes); } void Ld1rd(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rd, kDRegSizeInBytes); } void Ld1rqb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rqd(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rqh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rqw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rob(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rod(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1roh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1row(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1rsb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rsb, kBRegSizeInBytes); } void Ld1rsh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rsh, kHRegSizeInBytes); } void Ld1rsw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadBroadcastImmHelper(zt, pg, addr, &MacroAssembler::ld1rsw, kSRegSizeInBytes); } void Ld1sb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1sh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld1sw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ld2b(const ZRegister& zt1, const ZRegister& zt2, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2b(zt1, zt2, pg, addr); } void Ld2h(const ZRegister& zt1, const ZRegister& zt2, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2h(zt1, zt2, pg, addr); } void Ld2w(const ZRegister& zt1, const ZRegister& zt2, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2w(zt1, zt2, pg, addr); } void Ld2d(const ZRegister& zt1, const ZRegister& zt2, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld2d(zt1, zt2, pg, addr); } void Ld3b(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3b(zt1, zt2, zt3, pg, addr); } void Ld3h(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3h(zt1, zt2, zt3, pg, addr); } void Ld3w(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3w(zt1, zt2, zt3, pg, addr); } void Ld3d(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld3d(zt1, zt2, zt3, pg, addr); } void Ld4b(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4b(zt1, zt2, zt3, zt4, pg, addr); } void Ld4h(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4h(zt1, zt2, zt3, zt4, pg, addr); } void Ld4w(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4w(zt1, zt2, zt3, zt4, pg, addr); } void Ld4d(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ld4d(zt1, zt2, zt3, zt4, pg, addr); } void Ldff1b(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1h(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1w(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1d(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1sb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1sh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1sw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldff1b(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1b(zt, pg, xn, zm); } void Ldff1b(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1b(zt, pg, zn, imm5); } void Ldff1d(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1d(zt, pg, xn, zm); } void Ldff1d(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1d(zt, pg, zn, imm5); } void Ldff1h(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1h(zt, pg, xn, zm); } void Ldff1h(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1h(zt, pg, zn, imm5); } void Ldff1sb(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sb(zt, pg, xn, zm); } void Ldff1sb(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sb(zt, pg, zn, imm5); } void Ldff1sh(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sh(zt, pg, xn, zm); } void Ldff1sh(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sh(zt, pg, zn, imm5); } void Ldff1sw(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sw(zt, pg, xn, zm); } void Ldff1sw(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1sw(zt, pg, zn, imm5); } void Ldff1w(const ZRegister& zt, const PRegisterZ& pg, const Register& xn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1w(zt, pg, xn, zm); } void Ldff1w(const ZRegister& zt, const PRegisterZ& pg, const ZRegister& zn, int imm5) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldff1w(zt, pg, zn, imm5); } void Ldnf1b(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1b(zt, pg, addr); } void Ldnf1d(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1d(zt, pg, addr); } void Ldnf1h(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1h(zt, pg, addr); } void Ldnf1sb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1sb(zt, pg, addr); } void Ldnf1sh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1sh(zt, pg, addr); } void Ldnf1sw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1sw(zt, pg, addr); } void Ldnf1w(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnf1w(zt, pg, addr); } void Ldnt1b(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldnt1d(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldnt1h(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldnt1w(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void Ldr(const CPURegister& rt, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadStoreScalarImmHelper(rt, addr, &MacroAssembler::ldr); } void Lsl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); lsl(zd, pg, zd, shift); } void Lsl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Lsl(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lsl(zd, zn, shift); } void Lsl(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lsl(zd, zn, zm); } void Lsr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); lsr(zd, pg, zd, shift); } void Lsr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Lsr(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lsr(zd, zn, shift); } void Lsr(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); lsr(zd, zn, zm); } void Mov(const PRegister& pd, const PRegister& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(pd.VnB(), pn.VnB()); } void Mov(const PRegisterWithLaneSize& pd, const PRegisterM& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(pd, pg, pn); } void Mov(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(pd, pg, pn); } void Mov(const ZRegister& zd, const Register& xn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, xn); } void Mov(const ZRegister& zd, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, vn); } void Mov(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, zn); } void Mov(const ZRegister& zd, const ZRegister& zn, unsigned index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, zn, index); } void Mov(const ZRegister& zd, const PRegister& pg, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); Cpy(zd, pg, imm); } // TODO: support zeroing predicated moves using movprfx. void Mov(const ZRegister& zd, const PRegisterM& pg, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, pg, rn); } void Mov(const ZRegister& zd, const PRegisterM& pg, const VRegister& vn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, pg, vn); } void Mov(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mov(zd, pg, zn); } void Mov(const ZRegister& zd, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); Dup(zd, imm); } void Movs(const PRegister& pd, const PRegister& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); movs(pd, pn); } void Movs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); movs(pd, pg, pn); } // zd = za + (zn * zm) void Mla(const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); // zd = za - (zn * zm) void Mls(const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Mul(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void Nand(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nand(pd, pg, pn, pm); } void Nands(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nands(pd, pg, pn, pm); } // There is no instruction with this form, but we can implement it using // `subr`. void Neg(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, zn); subr(zd, zd, 0); } void Neg(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); neg(zd, pg, zn); } void Nor(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nor(pd, pg, pn, pm); } void Nors(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nors(pd, pg, pn, pm); } void Not(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); not_(pd, pg, pn); } void Not(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); not_(zd, pg, zn); } void Nots(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nots(pd, pg, pn); } void Orn(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orn(pd, pg, pn, pm); } void Orn(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { orn(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void Orns(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orns(pd, pg, pn, pm); } void Orr(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orr(pd, pg, pn, pm); } void Orr(const ZRegister& zd, const ZRegister& zn, uint64_t imm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); if (IsImmLogical(imm, zd.GetLaneSizeInBits())) { orr(zd, zn, imm); } else { // TODO: Synthesise the immediate once 'Mov' is implemented. VIXL_UNIMPLEMENTED(); } } void Orr(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameLaneSize(zd, zn, zm)); SingleEmissionCheckScope guard(this); orr(zd.VnD(), zn.VnD(), zm.VnD()); } void Orrs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orrs(pd, pg, pn, pm); } void Orv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); orv(vd, pg, zn); } void Pfalse(const PRegister& pd) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(pd.IsUnqualified()); SingleEmissionCheckScope guard(this); // No matter what the lane size is, overall this operation just writes zeros // throughout the register. pfalse(pd.VnB()); } void Pfirst(const PRegisterWithLaneSize& pd, const PRegister& pg, const PRegisterWithLaneSize& pn); void Pnext(const PRegisterWithLaneSize& pd, const PRegister& pg, const PRegisterWithLaneSize& pn); void Prfb(PrefetchOperation prfop, const PRegister& pg, const SVEMemOperand addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); prfb(prfop, pg, addr); } void Prfh(PrefetchOperation prfop, const PRegister& pg, const SVEMemOperand addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); prfh(prfop, pg, addr); } void Prfw(PrefetchOperation prfop, const PRegister& pg, const SVEMemOperand addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); prfw(prfop, pg, addr); } void Prfd(PrefetchOperation prfop, const PRegister& pg, const SVEMemOperand addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); prfd(prfop, pg, addr); } void Ptest(const PRegister& pg, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ptest(pg, pn); } void Ptrue(const PRegisterWithLaneSize& pd, SVEPredicateConstraint pattern, FlagsUpdate s); void Ptrue(const PRegisterWithLaneSize& pd, SVEPredicateConstraint pattern = SVE_ALL) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ptrue(pd, pattern); } void Ptrues(const PRegisterWithLaneSize& pd, SVEPredicateConstraint pattern = SVE_ALL) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ptrues(pd, pattern); } void Punpkhi(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); punpkhi(pd, pn); } void Punpklo(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); punpklo(pd, pn); } void Rbit(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rbit(zd, pg, zn); } void Rdffr(const PRegister& pd) { VIXL_ASSERT(allow_macro_instructions_); // Although this is essentially just a move, it writes every bit and so can // only support b-sized lane because other lane sizes would simplicity clear // bits in `pd`. VIXL_ASSERT(!pd.HasLaneSize() || pd.IsLaneSizeB()); VIXL_ASSERT(pd.IsUnqualified()); SingleEmissionCheckScope guard(this); rdffr(pd.VnB()); } void Rdffr(const PRegisterWithLaneSize& pd, const PRegisterZ& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rdffr(pd, pg); } void Rdffrs(const PRegisterWithLaneSize& pd, const PRegisterZ& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rdffrs(pd, pg); } // Note that there is no `rdpl` instruction, but this macro emulates it (for // symmetry with `Rdvl`). void Rdpl(const Register& xd, int64_t multiplier) { VIXL_ASSERT(allow_macro_instructions_); Addpl(xd, xzr, multiplier); } void Rdvl(const Register& xd, int64_t multiplier) { VIXL_ASSERT(allow_macro_instructions_); Addvl(xd, xzr, multiplier); } void Rev(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rev(pd, pn); } void Rev(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rev(zd, zn); } void Revb(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); revb(zd, pg, zn); } void Revh(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); revh(zd, pg, zn); } void Revw(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); revw(zd, pg, zn); } void Saddv(const VRegister& dd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddv(dd, pg, zn); } void Scvtf(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); scvtf(zd, pg, zn); } void Sdiv(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sel(const PRegisterWithLaneSize& pd, const PRegister& pg, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sel(pd, pg, pn, pm); } void Sel(const ZRegister& zd, const PRegister& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sel(zd, pg, zn, zm); } void Setffr() { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); setffr(); } void Smax(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void Smaxv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smaxv(vd, pg, zn); } void Smin(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void Sminv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sminv(vd, pg, zn); } void Splice(const ZRegister& zd, const PRegister& pg, const ZRegister& zn, const ZRegister& zm); void Sqadd(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqadd(zd, zn, zm); } void Sqadd(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(imm.IsUint8() || (imm.IsUint16() && ((imm.AsUint16() & 0xff) == 0))); MovprfxHelperScope guard(this, zd, zn); sqadd(zd, zd, imm.AsUint16()); } void Sqdecb(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecb(xd, wn, pattern, multiplier); } void Sqdecb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecb(rdn, pattern, multiplier); } void Sqdecd(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecd(xd, wn, pattern, multiplier); } void Sqdecd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecd(rdn, pattern, multiplier); } void Sqdecd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecd(zdn, pattern, multiplier); } void Sqdech(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdech(xd, wn, pattern, multiplier); } void Sqdech(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdech(rdn, pattern, multiplier); } void Sqdech(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdech(zdn, pattern, multiplier); } void Sqdecp(const Register& xdn, const PRegisterWithLaneSize& pg, const Register& wdn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecp(xdn, pg, wdn); } void Sqdecp(const Register& xdn, const PRegisterWithLaneSize& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecp(xdn, pg); } void Sqdecp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `sqdecp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); sqdecp(zd, pg); } void Sqdecp(const ZRegister& zdn, const PRegister& pg) { Sqdecp(zdn, pg, zdn); } void Sqdecw(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecw(xd, wn, pattern, multiplier); } void Sqdecw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecw(rdn, pattern, multiplier); } void Sqdecw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdecw(zdn, pattern, multiplier); } void Sqincb(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincb(xd, wn, pattern, multiplier); } void Sqincb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincb(rdn, pattern, multiplier); } void Sqincd(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincd(xd, wn, pattern, multiplier); } void Sqincd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincd(rdn, pattern, multiplier); } void Sqincd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincd(zdn, pattern, multiplier); } void Sqinch(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqinch(xd, wn, pattern, multiplier); } void Sqinch(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqinch(rdn, pattern, multiplier); } void Sqinch(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqinch(zdn, pattern, multiplier); } void Sqincp(const Register& xdn, const PRegisterWithLaneSize& pg, const Register& wdn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincp(xdn, pg, wdn); } void Sqincp(const Register& xdn, const PRegisterWithLaneSize& pg) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincp(xdn, pg); } void Sqincp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `sqincp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); sqincp(zd, pg); } void Sqincp(const ZRegister& zdn, const PRegister& pg) { Sqincp(zdn, pg, zdn); } void Sqincw(const Register& xd, const Register& wn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincw(xd, wn, pattern, multiplier); } void Sqincw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincw(rdn, pattern, multiplier); } void Sqincw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqincw(zdn, pattern, multiplier); } void Sqsub(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqsub(zd, zn, zm); } void Sqsub(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(imm.IsUint8() || (imm.IsUint16() && ((imm.AsUint16() & 0xff) == 0))); MovprfxHelperScope guard(this, zd, zn); sqsub(zd, zd, imm.AsUint16()); } void St1b(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void St1h(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void St1w(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void St1d(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void St2b(const ZRegister& zt1, const ZRegister& zt2, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2b(zt1, zt2, pg, addr); } void St2h(const ZRegister& zt1, const ZRegister& zt2, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2h(zt1, zt2, pg, addr); } void St2w(const ZRegister& zt1, const ZRegister& zt2, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2w(zt1, zt2, pg, addr); } void St2d(const ZRegister& zt1, const ZRegister& zt2, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st2d(zt1, zt2, pg, addr); } void St3b(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3b(zt1, zt2, zt3, pg, addr); } void St3h(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3h(zt1, zt2, zt3, pg, addr); } void St3w(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3w(zt1, zt2, zt3, pg, addr); } void St3d(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st3d(zt1, zt2, zt3, pg, addr); } void St4b(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4b(zt1, zt2, zt3, zt4, pg, addr); } void St4h(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4h(zt1, zt2, zt3, zt4, pg, addr); } void St4w(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4w(zt1, zt2, zt3, zt4, pg, addr); } void St4d(const ZRegister& zt1, const ZRegister& zt2, const ZRegister& zt3, const ZRegister& zt4, const PRegister& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); st4d(zt1, zt2, zt3, zt4, pg, addr); } void Stnt1b(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void Stnt1d(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void Stnt1h(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void Stnt1w(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); void Str(const CPURegister& rt, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SVELoadStoreScalarImmHelper(rt, addr, &MacroAssembler::str); } void Sub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sub(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sub(zd, zn, zm); } void Sub(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); AddSubHelper(kSubImmediate, zd, zn, imm); } void Sub(const ZRegister& zd, IntegerOperand imm, const ZRegister& zm); void Sunpkhi(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sunpkhi(zd, zn); } void Sunpklo(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sunpklo(zd, zn); } void Sxtb(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sxtb(zd, pg, zn); } void Sxth(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sxth(zd, pg, zn); } void Sxtw(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sxtw(zd, pg, zn); } void Tbl(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(zd, zn, zm); } void Trn1(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); trn1(pd, pn, pm); } void Trn1(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); trn1(zd, zn, zm); } void Trn2(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); trn2(pd, pn, pm); } void Trn2(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); trn2(zd, zn, zm); } void Uaddv(const VRegister& dd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uaddv(dd, pg, zn); } void Ucvtf(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ucvtf(zd, pg, zn); } void Udiv(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Udot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Udot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Umax(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void Umaxv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umaxv(vd, pg, zn); } void Umin(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void Uminv(const VRegister& vd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uminv(vd, pg, zn); } void Uqadd(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqadd(zd, zn, zm); } void Uqadd(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(imm.IsUint8() || (imm.IsUint16() && ((imm.AsUint16() & 0xff) == 0))); MovprfxHelperScope guard(this, zd, zn); uqadd(zd, zd, imm.AsUint16()); } void Uqdecb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdecb(rdn, pattern, multiplier); } void Uqdecd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdecd(rdn, pattern, multiplier); } void Uqdecd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdecd(zdn, pattern, multiplier); } void Uqdech(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdech(rdn, pattern, multiplier); } void Uqdech(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdech(zdn, pattern, multiplier); } // The saturation is based on the size of `rn`. The result is zero-extended // into `rd`, which must be at least as big. void Uqdecp(const Register& rd, const PRegisterWithLaneSize& pg, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(rd.Aliases(rn)); VIXL_ASSERT(rd.GetSizeInBytes() >= rn.GetSizeInBytes()); SingleEmissionCheckScope guard(this); if (rn.Is64Bits()) { uqdecp(rd, pg); } else { // Convert into , to make this more consistent with Sqdecp. uqdecp(rd.W(), pg); } } void Uqdecp(const Register& rdn, const PRegisterWithLaneSize& pg) { Uqdecp(rdn, pg, rdn); } void Uqdecp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `sqdecp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); uqdecp(zd, pg); } void Uqdecp(const ZRegister& zdn, const PRegister& pg) { Uqdecp(zdn, pg, zdn); } void Uqdecw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdecw(rdn, pattern, multiplier); } void Uqdecw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqdecw(zdn, pattern, multiplier); } void Uqincb(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqincb(rdn, pattern, multiplier); } void Uqincd(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqincd(rdn, pattern, multiplier); } void Uqincd(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqincd(zdn, pattern, multiplier); } void Uqinch(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqinch(rdn, pattern, multiplier); } void Uqinch(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqinch(zdn, pattern, multiplier); } // The saturation is based on the size of `rn`. The result is zero-extended // into `rd`, which must be at least as big. void Uqincp(const Register& rd, const PRegisterWithLaneSize& pg, const Register& rn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(rd.Aliases(rn)); VIXL_ASSERT(rd.GetSizeInBytes() >= rn.GetSizeInBytes()); SingleEmissionCheckScope guard(this); if (rn.Is64Bits()) { uqincp(rd, pg); } else { // Convert into , to make this more consistent with Sqincp. uqincp(rd.W(), pg); } } void Uqincp(const Register& rdn, const PRegisterWithLaneSize& pg) { Uqincp(rdn, pg, rdn); } void Uqincp(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(AreSameFormat(zd, zn)); // `sqincp` writes every lane, so use an unpredicated movprfx. MovprfxHelperScope guard(this, zd, zn); uqincp(zd, pg); } void Uqincp(const ZRegister& zdn, const PRegister& pg) { Uqincp(zdn, pg, zdn); } void Uqincw(const Register& rdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqincw(rdn, pattern, multiplier); } void Uqincw(const ZRegister& zdn, int pattern = SVE_ALL, int multiplier = 1) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqincw(zdn, pattern, multiplier); } void Uqsub(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqsub(zd, zn, zm); } void Uqsub(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(imm.IsUint8() || (imm.IsUint16() && ((imm.AsUint16() & 0xff) == 0))); MovprfxHelperScope guard(this, zd, zn); uqsub(zd, zd, imm.AsUint16()); } void Uunpkhi(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uunpkhi(zd, zn); } void Uunpklo(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uunpklo(zd, zn); } void Uxtb(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uxtb(zd, pg, zn); } void Uxth(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uxth(zd, pg, zn); } void Uxtw(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uxtw(zd, pg, zn); } void Uzp1(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uzp1(pd, pn, pm); } void Uzp1(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uzp1(zd, zn, zm); } void Uzp2(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uzp2(pd, pn, pm); } void Uzp2(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uzp2(zd, zn, zm); } void Whilele(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilele(pd, rn, rm); } void Whilelo(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilelo(pd, rn, rm); } void Whilels(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilels(pd, rn, rm); } void Whilelt(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilelt(pd, rn, rm); } void Wrffr(const PRegister& pn) { VIXL_ASSERT(allow_macro_instructions_); // Although this is essentially just a move, it writes every bit and so can // only support b-sized lane because other lane sizes would implicitly clear // bits in `ffr`. VIXL_ASSERT(!pn.HasLaneSize() || pn.IsLaneSizeB()); VIXL_ASSERT(pn.IsUnqualified()); SingleEmissionCheckScope guard(this); wrffr(pn.VnB()); } void Zip1(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); zip1(pd, pn, pm); } void Zip1(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); zip1(zd, zn, zm); } void Zip2(const PRegisterWithLaneSize& pd, const PRegisterWithLaneSize& pn, const PRegisterWithLaneSize& pm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); zip2(pd, pn, pm); } void Zip2(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); zip2(zd, zn, zm); } // SVE2 void Adclb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Adclt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Addhnb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); addhnb(zd, zn, zm); } void Addhnt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); addhnt(zd, zn, zm); } void Addp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Bcax(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Bdep(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bdep(zd, zn, zm); } void Bext(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bext(zd, zn, zm); } void Bgrp(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); bgrp(zd, zn, zm); } void Bsl(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Bsl1n(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Bsl2n(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Cadd(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int rot); void Cdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index, int rot); void Cdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int rot); void Cmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index, int rot); void Cmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int rot); void Eor3(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Eorbt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); eorbt(zd, zn, zm); } void Eortb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); eortb(zd, zn, zm); } void Faddp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fcvtlt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtlt(zd, pg, zn); } void Fcvtnt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtnt(zd, pg, zn); } void Fcvtx(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); VIXL_ASSERT(zn.IsLaneSizeD()); MovprfxHelperScope guard(this, zd.VnD(), pg, zd.VnD()); fcvtx(zd, pg.Merging(), zn); } void Fcvtxnt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); fcvtxnt(zd, pg, zn); } void Flogb(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zd); flogb(zd, pg.Merging(), zn); } void Fmaxnmp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fmaxp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fminnmp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fminp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Fmlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Fmlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Fmlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Fmlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Fmlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Fmlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Fmlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Fmlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Histcnt(const ZRegister& zd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); histcnt(zd, pg, zn, zm); } void Histseg(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); histseg(zd, zn, zm); } void Ldnt1sb(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnt1sb(zt, pg, addr); } void Ldnt1sh(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnt1sh(zt, pg, addr); } void Ldnt1sw(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ldnt1sw(zt, pg, addr); } void Match(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); match(pd, pg, zn, zm); } void Mla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Mls(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Mul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mul(zd, zn, zm, index); } void Mul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); mul(zd, zn, zm); } void Nbsl(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, const ZRegister& zk); void Nmatch(const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); nmatch(pd, pg, zn, zm); } void Pmul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); pmul(zd, zn, zm); } void Pmullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); pmullb(zd, zn, zm); } void Pmullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); pmullt(zd, zn, zm); } void Raddhnb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); raddhnb(zd, zn, zm); } void Raddhnt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); raddhnt(zd, zn, zm); } void Rshrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rshrnb(zd, zn, shift); } void Rshrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rshrnt(zd, zn, shift); } void Rsubhnb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rsubhnb(zd, zn, zm); } void Rsubhnt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); rsubhnt(zd, zn, zm); } void Saba(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sabalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sabalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sabdlb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sabdlb(zd, zn, zm); } void Sabdlt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sabdlt(zd, zn, zm); } void Sadalp(const ZRegister& zda, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sadalp(zda, pg, zn); } void Saddlb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddlb(zd, zn, zm); } void Saddlbt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddlbt(zd, zn, zm); } void Saddlt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddlt(zd, zn, zm); } void Saddwb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddwb(zd, zn, zm); } void Saddwt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); saddwt(zd, zn, zm); } void Sbclb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sbclt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Shrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); shrnb(zd, zn, shift); } void Shrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); shrnt(zd, zn, shift); } void Shsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sli(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sli(zd, zn, shift); } void Smaxp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sminp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Smlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Smlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Smlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Smlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Smlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Smlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Smlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Smlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Smulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smulh(zd, zn, zm); } void Smullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smullb(zd, zn, zm, index); } void Smullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smullb(zd, zn, zm); } void Smullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smullt(zd, zn, zm, index); } void Smullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); smullt(zd, zn, zm); } void Sqabs(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zd); sqabs(zd, pg.Merging(), zn); } void Sqcadd(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int rot); void Sqdmlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqdmlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmlalbt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqdmlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqdmlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmlslbt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqdmlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqdmulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmulh(zd, zn, zm, index); } void Sqdmulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmulh(zd, zn, zm); } void Sqdmullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmullb(zd, zn, zm, index); } void Sqdmullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmullb(zd, zn, zm); } void Sqdmullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmullt(zd, zn, zm, index); } void Sqdmullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqdmullt(zd, zn, zm); } void Sqneg(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zd); sqneg(zd, pg.Merging(), zn); } void Sqrdcmlah(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index, int rot); void Sqrdcmlah(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int rot); void Sqrdmlah(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqrdmlah(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqrdmlsh(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Sqrdmlsh(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sqrdmulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrdmulh(zd, zn, zm, index); } void Sqrdmulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrdmulh(zd, zn, zm); } void Sqrshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sqrshrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrshrnb(zd, zn, shift); } void Sqrshrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrshrnt(zd, zn, shift); } void Sqrshrunb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrshrunb(zd, zn, shift); } void Sqrshrunt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqrshrunt(zd, zn, shift); } void Sqshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); sqshl(zd, pg, zd, shift); } void Sqshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sqshlu(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); sqshlu(zd, pg, zd, shift); } void Sqshrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqshrnb(zd, zn, shift); } void Sqshrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqshrnt(zd, zn, shift); } void Sqshrunb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqshrunb(zd, zn, shift); } void Sqshrunt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqshrunt(zd, zn, shift); } void Sqsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Sqxtnb(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqxtnb(zd, zn); } void Sqxtnt(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqxtnt(zd, zn); } void Sqxtunb(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqxtunb(zd, zn); } void Sqxtunt(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sqxtunt(zd, zn); } void Sri(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sri(zd, zn, shift); } void Srshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Srshr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); srshr(zd, pg, zd, shift); } void Srsra(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, int shift); void Sshllb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sshllb(zd, zn, shift); } void Sshllt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); sshllt(zd, zn, shift); } void Ssra(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, int shift); void Ssublb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssublb(zd, zn, zm); } void Ssublbt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssublbt(zd, zn, zm); } void Ssublt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssublt(zd, zn, zm); } void Ssubltb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssubltb(zd, zn, zm); } void Ssubwb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssubwb(zd, zn, zm); } void Ssubwt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ssubwt(zd, zn, zm); } void Subhnb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); subhnb(zd, zn, zm); } void Subhnt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); subhnt(zd, zn, zm); } void Suqadd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Tbl(const ZRegister& zd, const ZRegister& zn1, const ZRegister& zn2, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbl(zd, zn1, zn2, zm); } void Tbx(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); tbx(zd, zn, zm); } void Uaba(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Uabalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Uabalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Uabdlb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uabdlb(zd, zn, zm); } void Uabdlt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uabdlt(zd, zn, zm); } void Uadalp(const ZRegister& zda, const PRegisterM& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uadalp(zda, pg, zn); } void Uaddlb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uaddlb(zd, zn, zm); } void Uaddlt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uaddlt(zd, zn, zm); } void Uaddwb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uaddwb(zd, zn, zm); } void Uaddwt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uaddwt(zd, zn, zm); } void Uhsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Umaxp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Uminp(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Umlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Umlalb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Umlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Umlalt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Umlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Umlslb(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Umlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Umlslt(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Umulh(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umulh(zd, zn, zm); } void Umullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umullb(zd, zn, zm, index); } void Umullb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umullb(zd, zn, zm); } void Umullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int index) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umullt(zd, zn, zm, index); } void Umullt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); umullt(zd, zn, zm); } void Uqrshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Uqrshrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqrshrnb(zd, zn, shift); } void Uqrshrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqrshrnt(zd, zn, shift); } void Uqshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); uqshl(zd, pg, zd, shift); } void Uqshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Uqshrnb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqshrnb(zd, zn, shift); } void Uqshrnt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqshrnt(zd, zn, shift); } void Uqsub(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Uqxtnb(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqxtnb(zd, zn); } void Uqxtnt(const ZRegister& zd, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); uqxtnt(zd, zn); } void Urecpe(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zd); urecpe(zd, pg.Merging(), zn); } void Urshl(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Urshr(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zn); urshr(zd, pg, zd, shift); } void Ursqrte(const ZRegister& zd, const PRegister& pg, const ZRegister& zn) { VIXL_ASSERT(allow_macro_instructions_); MovprfxHelperScope guard(this, zd, pg, zd); ursqrte(zd, pg.Merging(), zn); } void Ursra(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, int shift); void Ushllb(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ushllb(zd, zn, shift); } void Ushllt(const ZRegister& zd, const ZRegister& zn, int shift) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); ushllt(zd, zn, shift); } void Usqadd(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void Usra(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, int shift); void Usublb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); usublb(zd, zn, zm); } void Usublt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); usublt(zd, zn, zm); } void Usubwb(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); usubwb(zd, zn, zm); } void Usubwt(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); usubwt(zd, zn, zm); } void Whilege(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilege(pd, rn, rm); } void Whilegt(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilegt(pd, rn, rm); } void Whilehi(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilehi(pd, rn, rm); } void Whilehs(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilehs(pd, rn, rm); } void Whilerw(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilerw(pd, rn, rm); } void Whilewr(const PRegisterWithLaneSize& pd, const Register& rn, const Register& rm) { VIXL_ASSERT(allow_macro_instructions_); SingleEmissionCheckScope guard(this); whilewr(pd, rn, rm); } void Xar(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int shift) { VIXL_ASSERT(allow_macro_instructions_); if (zd.Aliases(zm)) { SingleEmissionCheckScope guard(this); xar(zd, zm, zn, shift); } else { MovprfxHelperScope guard(this, zd, zn); xar(zd, zd, zm, shift); } } void Fmmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Smmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Ummla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Usmmla(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Usdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void Usdot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); void Sudot(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); template Literal* CreateLiteralDestroyedWithPool(T value) { return new Literal(value, &literal_pool_, RawLiteral::kDeletedOnPoolDestruction); } template Literal* CreateLiteralDestroyedWithPool(T high64, T low64) { return new Literal(high64, low64, &literal_pool_, RawLiteral::kDeletedOnPoolDestruction); } // Push the system stack pointer (sp) down to allow the same to be done to // the current stack pointer (according to StackPointer()). This must be // called _before_ accessing the memory. // // This is necessary when pushing or otherwise adding things to the stack, to // satisfy the AAPCS64 constraint that the memory below the system stack // pointer is not accessed. // // This method asserts that StackPointer() is not sp, since the call does // not make sense in that context. // // TODO: This method can only accept values of 'space' that can be encoded in // one instruction. Refer to the implementation for details. void BumpSystemStackPointer(const Operand& space); virtual bool AllowMacroInstructions() const VIXL_OVERRIDE { return allow_macro_instructions_; } virtual bool ArePoolsBlocked() const VIXL_OVERRIDE { return IsLiteralPoolBlocked() && IsVeneerPoolBlocked(); } void SetGenerateSimulatorCode(bool value) { generate_simulator_code_ = value; } bool GenerateSimulatorCode() const { return generate_simulator_code_; } size_t GetLiteralPoolSize() const { return literal_pool_.GetSize(); } VIXL_DEPRECATED("GetLiteralPoolSize", size_t LiteralPoolSize() const) { return GetLiteralPoolSize(); } size_t GetLiteralPoolMaxSize() const { return literal_pool_.GetMaxSize(); } VIXL_DEPRECATED("GetLiteralPoolMaxSize", size_t LiteralPoolMaxSize() const) { return GetLiteralPoolMaxSize(); } size_t GetVeneerPoolMaxSize() const { return veneer_pool_.GetMaxSize(); } VIXL_DEPRECATED("GetVeneerPoolMaxSize", size_t VeneerPoolMaxSize() const) { return GetVeneerPoolMaxSize(); } // The number of unresolved branches that may require a veneer. int GetNumberOfPotentialVeneers() const { return veneer_pool_.GetNumberOfPotentialVeneers(); } VIXL_DEPRECATED("GetNumberOfPotentialVeneers", int NumberOfPotentialVeneers() const) { return GetNumberOfPotentialVeneers(); } ptrdiff_t GetNextCheckPoint() const { ptrdiff_t next_checkpoint_for_pools = std::min(literal_pool_.GetCheckpoint(), veneer_pool_.GetCheckpoint()); return std::min(next_checkpoint_for_pools, static_cast(GetBuffer().GetCapacity())); } VIXL_DEPRECATED("GetNextCheckPoint", ptrdiff_t NextCheckPoint()) { return GetNextCheckPoint(); } void EmitLiteralPool(LiteralPool::EmitOption option) { if (!literal_pool_.IsEmpty()) literal_pool_.Emit(option); checkpoint_ = GetNextCheckPoint(); recommended_checkpoint_ = literal_pool_.GetNextRecommendedCheckpoint(); } void CheckEmitFor(size_t amount); void EnsureEmitFor(size_t amount) { ptrdiff_t offset = amount; ptrdiff_t max_pools_size = literal_pool_.GetMaxSize() + veneer_pool_.GetMaxSize(); ptrdiff_t cursor = GetCursorOffset(); if ((cursor >= recommended_checkpoint_) || ((cursor + offset + max_pools_size) >= checkpoint_)) { CheckEmitFor(amount); } } void CheckEmitPoolsFor(size_t amount); virtual void EnsureEmitPoolsFor(size_t amount) VIXL_OVERRIDE { ptrdiff_t offset = amount; ptrdiff_t max_pools_size = literal_pool_.GetMaxSize() + veneer_pool_.GetMaxSize(); ptrdiff_t cursor = GetCursorOffset(); if ((cursor >= recommended_checkpoint_) || ((cursor + offset + max_pools_size) >= checkpoint_)) { CheckEmitPoolsFor(amount); } } // Set the current stack pointer, but don't generate any code. void SetStackPointer(const Register& stack_pointer) { VIXL_ASSERT(!GetScratchRegisterList()->IncludesAliasOf(stack_pointer)); sp_ = stack_pointer; } // Return the current stack pointer, as set by SetStackPointer. const Register& StackPointer() const { return sp_; } CPURegList* GetScratchRegisterList() { return &tmp_list_; } VIXL_DEPRECATED("GetScratchRegisterList", CPURegList* TmpList()) { return GetScratchRegisterList(); } CPURegList* GetScratchVRegisterList() { return &v_tmp_list_; } VIXL_DEPRECATED("GetScratchVRegisterList", CPURegList* FPTmpList()) { return GetScratchVRegisterList(); } CPURegList* GetScratchPRegisterList() { return &p_tmp_list_; } // Get or set the current (most-deeply-nested) UseScratchRegisterScope. void SetCurrentScratchRegisterScope(UseScratchRegisterScope* scope) { current_scratch_scope_ = scope; } UseScratchRegisterScope* GetCurrentScratchRegisterScope() { return current_scratch_scope_; } // Like printf, but print at run-time from generated code. // // The caller must ensure that arguments for floating-point placeholders // (such as %e, %f or %g) are VRegisters in format 1S or 1D, and that // arguments for integer placeholders are Registers. // // At the moment it is only possible to print the value of sp if it is the // current stack pointer. Otherwise, the MacroAssembler will automatically // update sp on every push (using BumpSystemStackPointer), so determining its // value is difficult. // // Format placeholders that refer to more than one argument, or to a specific // argument, are not supported. This includes formats like "%1$d" or "%.*d". // // This function automatically preserves caller-saved registers so that // calling code can use Printf at any point without having to worry about // corruption. The preservation mechanism generates a lot of code. If this is // a problem, preserve the important registers manually and then call // PrintfNoPreserve. Callee-saved registers are not used by Printf, and are // implicitly preserved. void Printf(const char* format, CPURegister arg0 = NoCPUReg, CPURegister arg1 = NoCPUReg, CPURegister arg2 = NoCPUReg, CPURegister arg3 = NoCPUReg); // Like Printf, but don't preserve any caller-saved registers, not even 'lr'. // // The return code from the system printf call will be returned in x0. void PrintfNoPreserve(const char* format, const CPURegister& arg0 = NoCPUReg, const CPURegister& arg1 = NoCPUReg, const CPURegister& arg2 = NoCPUReg, const CPURegister& arg3 = NoCPUReg); // Trace control when running the debug simulator. // // For example: // // __ Trace(LOG_REGS, TRACE_ENABLE); // Will add registers to the trace if it wasn't already the case. // // __ Trace(LOG_DISASM, TRACE_DISABLE); // Will stop logging disassembly. It has no effect if the disassembly wasn't // already being logged. void Trace(TraceParameters parameters, TraceCommand command); // Log the requested data independently of what is being traced. // // For example: // // __ Log(LOG_FLAGS) // Will output the flags. void Log(TraceParameters parameters); // Enable or disable CPU features dynamically. This mechanism allows users to // strictly check the use of CPU features in different regions of code. void SetSimulatorCPUFeatures(const CPUFeatures& features); void EnableSimulatorCPUFeatures(const CPUFeatures& features); void DisableSimulatorCPUFeatures(const CPUFeatures& features); void SaveSimulatorCPUFeatures(); void RestoreSimulatorCPUFeatures(); LiteralPool* GetLiteralPool() { return &literal_pool_; } // Support for simulated runtime calls. // `CallRuntime` requires variadic templating, that is only available from // C++11. #if __cplusplus >= 201103L #define VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT #endif // #if __cplusplus >= 201103L #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT template void CallRuntimeHelper(R (*function)(P...), RuntimeCallType call_type); template void CallRuntime(R (*function)(P...)) { CallRuntimeHelper(function, kCallRuntime); } template void TailCallRuntime(R (*function)(P...)) { CallRuntimeHelper(function, kTailCallRuntime); } #endif // #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT protected: void BlockLiteralPool() { literal_pool_.Block(); } void ReleaseLiteralPool() { literal_pool_.Release(); } bool IsLiteralPoolBlocked() const { return literal_pool_.IsBlocked(); } void BlockVeneerPool() { veneer_pool_.Block(); } void ReleaseVeneerPool() { veneer_pool_.Release(); } bool IsVeneerPoolBlocked() const { return veneer_pool_.IsBlocked(); } virtual void BlockPools() VIXL_OVERRIDE { BlockLiteralPool(); BlockVeneerPool(); } virtual void ReleasePools() VIXL_OVERRIDE { ReleaseLiteralPool(); ReleaseVeneerPool(); } // The scopes below need to able to block and release a particular pool. // TODO: Consider removing those scopes or move them to // code-generation-scopes-vixl.h. friend class BlockPoolsScope; friend class BlockLiteralPoolScope; friend class BlockVeneerPoolScope; virtual void SetAllowMacroInstructions(bool value) VIXL_OVERRIDE { allow_macro_instructions_ = value; } // Helper used to query information about code generation and to generate // code for `csel`. // Here and for the related helpers below: // - Code is generated when `masm` is not `NULL`. // - On return and when set, `should_synthesise_left` and // `should_synthesise_right` will indicate whether `left` and `right` // should be synthesized in a temporary register. static void CselHelper(MacroAssembler* masm, const Register& rd, Operand left, Operand right, Condition cond, bool* should_synthesise_left = NULL, bool* should_synthesise_right = NULL); // The helper returns `true` if it can handle the specified arguments. // Also see comments for `CselHelper()`. static bool CselSubHelperTwoImmediates(MacroAssembler* masm, const Register& rd, int64_t left, int64_t right, Condition cond, bool* should_synthesise_left, bool* should_synthesise_right); // See comments for `CselHelper()`. static bool CselSubHelperTwoOrderedImmediates(MacroAssembler* masm, const Register& rd, int64_t left, int64_t right, Condition cond); // See comments for `CselHelper()`. static void CselSubHelperRightSmallImmediate(MacroAssembler* masm, UseScratchRegisterScope* temps, const Register& rd, const Operand& left, const Operand& right, Condition cond, bool* should_synthesise_left); // Generate code to calculate the address represented by `addr` and write it // into `xd`. This is used as a common fall-back for out-of-range load and // store operands. // // The vl_divisor_log2 argument is used to scale the VL, for use with // SVE_MUL_VL. void CalculateSVEAddress(const Register& xd, const SVEMemOperand& addr, int vl_divisor_log2 = 0); void CalculateSVEAddress(const Register& xd, const SVEMemOperand& addr, const CPURegister& rt) { VIXL_ASSERT(rt.IsPRegister() || rt.IsZRegister()); int vl_divisor_log2 = rt.IsPRegister() ? kZRegBitsPerPRegBitLog2 : 0; CalculateSVEAddress(xd, addr, vl_divisor_log2); } void SetFPNaNPropagationOption(FPMacroNaNPropagationOption nan_option) { fp_nan_propagation_ = nan_option; } void ResolveFPNaNPropagationOption(FPMacroNaNPropagationOption* nan_option) { // The input option has priority over the option that has set. if (*nan_option == NoFPMacroNaNPropagationSelected) { *nan_option = fp_nan_propagation_; } VIXL_ASSERT(*nan_option != NoFPMacroNaNPropagationSelected); } private: // The actual Push and Pop implementations. These don't generate any code // other than that required for the push or pop. This allows // (Push|Pop)CPURegList to bundle together setup code for a large block of // registers. // // Note that size is per register, and is specified in bytes. void PushHelper(int count, int size, const CPURegister& src0, const CPURegister& src1, const CPURegister& src2, const CPURegister& src3); void PopHelper(int count, int size, const CPURegister& dst0, const CPURegister& dst1, const CPURegister& dst2, const CPURegister& dst3); void Movi16bitHelper(const VRegister& vd, uint64_t imm); void Movi32bitHelper(const VRegister& vd, uint64_t imm); void Movi64bitHelper(const VRegister& vd, uint64_t imm); // Perform necessary maintenance operations before a push or pop. // // Note that size is per register, and is specified in bytes. void PrepareForPush(int count, int size); void PrepareForPop(int count, int size); // The actual implementation of load and store operations for CPURegList. enum LoadStoreCPURegListAction { kLoad, kStore }; void LoadStoreCPURegListHelper(LoadStoreCPURegListAction operation, CPURegList registers, const MemOperand& mem); // Returns a MemOperand suitable for loading or storing a CPURegList at `dst`. // This helper may allocate registers from `scratch_scope` and generate code // to compute an intermediate address. The resulting MemOperand is only valid // as long as `scratch_scope` remains valid. MemOperand BaseMemOperandForLoadStoreCPURegList( const CPURegList& registers, const MemOperand& mem, UseScratchRegisterScope* scratch_scope); bool LabelIsOutOfRange(Label* label, ImmBranchType branch_type) { return !Instruction::IsValidImmPCOffset(branch_type, label->GetLocation() - GetCursorOffset()); } void ConfigureSimulatorCPUFeaturesHelper(const CPUFeatures& features, DebugHltOpcode action); void CompareHelper(Condition cond, const PRegisterWithLaneSize& pd, const PRegisterZ& pg, const ZRegister& zn, IntegerOperand imm); // E.g. Ld1rb. typedef void (Assembler::*SVELoadBroadcastFn)(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); void SVELoadBroadcastImmHelper(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr, SVELoadBroadcastFn fn, int divisor); // E.g. ldr/str typedef void (Assembler::*SVELoadStoreFn)(const CPURegister& rt, const SVEMemOperand& addr); void SVELoadStoreScalarImmHelper(const CPURegister& rt, const SVEMemOperand& addr, SVELoadStoreFn fn); typedef void (Assembler::*SVELoad1Fn)(const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr); typedef void (Assembler::*SVEStore1Fn)(const ZRegister& zt, const PRegister& pg, const SVEMemOperand& addr); // Helper for predicated Z register loads with addressing modes not directly // encodable in the instruction. The supported_modifier parameter indicates // which offset modifier the calling instruction encoder supports (eg. // SVE_MUL_VL). The ratio log2 of VL to memory access size is passed as // vl_divisor_log2; pass -1 to indicate no dependency. template void SVELoadStoreNTBroadcastQOHelper( const ZRegister& zt, const Tg& pg, const SVEMemOperand& addr, Tf fn, int imm_bits, int shift_amount, SVEOffsetModifier supported_modifier = NO_SVE_OFFSET_MODIFIER, int vl_divisor_log2 = 0); template void SVELoadStore1Helper(int msize_in_bytes_log2, const ZRegister& zt, const Tg& pg, const SVEMemOperand& addr, Tf fn); template void SVELoadFFHelper(int msize_in_bytes_log2, const ZRegister& zt, const PRegisterZ& pg, const SVEMemOperand& addr, Tf fn); typedef void (MacroAssembler::*IntWideImmMacroFn)(const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); typedef void (Assembler::*IntWideImmShiftFn)(const ZRegister& zd, const ZRegister& zn, int imm, int shift); typedef void (Assembler::*Int3ArithFn)(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm); typedef void (Assembler::*Int4ArithFn)(const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); typedef void (Assembler::*IntArithImmFn)(const ZRegister& zd, const ZRegister& zn, int imm); typedef void (Assembler::*ZZZImmFn)(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int imm); typedef void (MacroAssembler::*SVEArithPredicatedFn)(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void IntWideImmHelper(IntArithImmFn imm_fn, SVEArithPredicatedFn reg_fn, const ZRegister& zd, const ZRegister& zn, IntegerOperand imm, bool is_signed_imm); enum AddSubHelperOption { kAddImmediate, kSubImmediate }; void AddSubHelper(AddSubHelperOption option, const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); // Try to emit an add- or sub-like instruction (imm_fn) with `imm`, or the // corresponding sub- or add-like instruction (n_imm_fn) with a negated `imm`. // A `movprfx` is automatically generated if one is required. If successful, // return true. Otherwise, return false. // // This helper uses two's complement equivalences, for example treating 0xffff // as -1 for H-sized lanes. bool TrySingleAddSub(AddSubHelperOption option, const ZRegister& zd, const ZRegister& zn, IntegerOperand imm); void AbsoluteDifferenceAccumulate(Int3ArithFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void FourRegDestructiveHelper(Int3ArithFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void FourRegDestructiveHelper(Int4ArithFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm); void SVEDotIndexHelper(ZZZImmFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int index); // For noncommutative arithmetic operations. void NoncommutativeArithmeticHelper(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, SVEArithPredicatedFn fn, SVEArithPredicatedFn rev_fn); void FPCommutativeArithmeticHelper(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm, SVEArithPredicatedFn fn, FPMacroNaNPropagationOption nan_option); // Floating-point fused multiply-add vectors (predicated), writing addend. typedef void (Assembler::*SVEMulAddPredicatedZdaFn)(const ZRegister& zda, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); // Floating-point fused multiply-add vectors (predicated), writing // multiplicand. typedef void (Assembler::*SVEMulAddPredicatedZdnFn)(const ZRegister& zdn, const PRegisterM& pg, const ZRegister& zn, const ZRegister& zm); void FPMulAddHelper(const ZRegister& zd, const PRegisterM& pg, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, SVEMulAddPredicatedZdaFn fn_zda, SVEMulAddPredicatedZdnFn fn_zdn, FPMacroNaNPropagationOption nan_option); typedef void (Assembler::*SVEMulAddIndexFn)(const ZRegister& zda, const ZRegister& zn, const ZRegister& zm, int index); void FourRegOneImmDestructiveHelper(ZZZImmFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, const ZRegister& zm, int imm); void ShiftRightAccumulate(IntArithImmFn fn, const ZRegister& zd, const ZRegister& za, const ZRegister& zn, int imm); void ComplexAddition(ZZZImmFn fn, const ZRegister& zd, const ZRegister& zn, const ZRegister& zm, int rot); // Tell whether any of the macro instruction can be used. When false the // MacroAssembler will assert if a method which can emit a variable number // of instructions is called. bool allow_macro_instructions_; // Indicates whether we should generate simulator or native code. bool generate_simulator_code_; // The register to use as a stack pointer for stack operations. Register sp_; // Scratch registers available for use by the MacroAssembler. CPURegList tmp_list_; CPURegList v_tmp_list_; CPURegList p_tmp_list_; UseScratchRegisterScope* current_scratch_scope_; LiteralPool literal_pool_; VeneerPool veneer_pool_; ptrdiff_t checkpoint_; ptrdiff_t recommended_checkpoint_; FPMacroNaNPropagationOption fp_nan_propagation_; friend class Pool; friend class LiteralPool; }; inline size_t VeneerPool::GetOtherPoolsMaxSize() const { return masm_->GetLiteralPoolMaxSize(); } inline size_t LiteralPool::GetOtherPoolsMaxSize() const { return masm_->GetVeneerPoolMaxSize(); } inline void LiteralPool::SetNextRecommendedCheckpoint(ptrdiff_t offset) { masm_->recommended_checkpoint_ = std::min(masm_->recommended_checkpoint_, offset); recommended_checkpoint_ = offset; } class InstructionAccurateScope : public ExactAssemblyScope { public: VIXL_DEPRECATED("ExactAssemblyScope", InstructionAccurateScope(MacroAssembler* masm, int64_t count, SizePolicy size_policy = kExactSize)) : ExactAssemblyScope(masm, count * kInstructionSize, size_policy) {} }; class BlockLiteralPoolScope { public: explicit BlockLiteralPoolScope(MacroAssembler* masm) : masm_(masm) { masm_->BlockLiteralPool(); } ~BlockLiteralPoolScope() { masm_->ReleaseLiteralPool(); } private: MacroAssembler* masm_; }; class BlockVeneerPoolScope { public: explicit BlockVeneerPoolScope(MacroAssembler* masm) : masm_(masm) { masm_->BlockVeneerPool(); } ~BlockVeneerPoolScope() { masm_->ReleaseVeneerPool(); } private: MacroAssembler* masm_; }; class BlockPoolsScope { public: explicit BlockPoolsScope(MacroAssembler* masm) : masm_(masm) { masm_->BlockPools(); } ~BlockPoolsScope() { masm_->ReleasePools(); } private: MacroAssembler* masm_; }; MovprfxHelperScope::MovprfxHelperScope(MacroAssembler* masm, const ZRegister& dst, const ZRegister& src) : ExactAssemblyScope(masm, ShouldGenerateMovprfx(dst, src) ? (2 * kInstructionSize) : kInstructionSize) { if (ShouldGenerateMovprfx(dst, src)) { masm->movprfx(dst, src); } } MovprfxHelperScope::MovprfxHelperScope(MacroAssembler* masm, const ZRegister& dst, const PRegister& pg, const ZRegister& src) : ExactAssemblyScope(masm, ShouldGenerateMovprfx(dst, pg, src) ? (2 * kInstructionSize) : kInstructionSize) { if (ShouldGenerateMovprfx(dst, pg, src)) { masm->movprfx(dst, pg, src); } } // This scope utility allows scratch registers to be managed safely. The // MacroAssembler's GetScratch*RegisterList() are used as a pool of scratch // registers. These registers can be allocated on demand, and will be returned // at the end of the scope. // // When the scope ends, the MacroAssembler's lists will be restored to their // original state, even if the lists were modified by some other means. class UseScratchRegisterScope { public: // This constructor implicitly calls `Open` to initialise the scope (`masm` // must not be `NULL`), so it is ready to use immediately after it has been // constructed. explicit UseScratchRegisterScope(MacroAssembler* masm) : masm_(NULL), parent_(NULL), old_available_(0), old_available_v_(0), old_available_p_(0) { Open(masm); } // This constructor does not implicitly initialise the scope. Instead, the // user is required to explicitly call the `Open` function before using the // scope. UseScratchRegisterScope() : masm_(NULL), parent_(NULL), old_available_(0), old_available_v_(0), old_available_p_(0) {} // This function performs the actual initialisation work. void Open(MacroAssembler* masm); // The destructor always implicitly calls the `Close` function. ~UseScratchRegisterScope() { Close(); } // This function performs the cleaning-up work. It must succeed even if the // scope has not been opened. It is safe to call multiple times. void Close(); bool IsAvailable(const CPURegister& reg) const; // Take a register from the appropriate temps list. It will be returned // automatically when the scope ends. Register AcquireW() { return AcquireFrom(masm_->GetScratchRegisterList()).W(); } Register AcquireX() { return AcquireFrom(masm_->GetScratchRegisterList()).X(); } VRegister AcquireH() { return AcquireFrom(masm_->GetScratchVRegisterList()).H(); } VRegister AcquireS() { return AcquireFrom(masm_->GetScratchVRegisterList()).S(); } VRegister AcquireD() { return AcquireFrom(masm_->GetScratchVRegisterList()).D(); } ZRegister AcquireZ() { return AcquireFrom(masm_->GetScratchVRegisterList()).Z(); } PRegister AcquireP() { // Prefer to allocate p8-p15 if we can, to leave p0-p7 available for use as // governing predicates. CPURegList* available = masm_->GetScratchPRegisterList(); RegList preferred = ~kGoverningPRegisterMask; if ((available->GetList() & preferred) != 0) { return AcquireFrom(available, preferred).P(); } return AcquireFrom(available).P(); } // Acquire a P register suitable for use as a governing predicate in // instructions which only accept p0-p7 for that purpose. PRegister AcquireGoverningP() { CPURegList* available = masm_->GetScratchPRegisterList(); return AcquireFrom(available, kGoverningPRegisterMask).P(); } Register AcquireRegisterOfSize(int size_in_bits); Register AcquireSameSizeAs(const Register& reg) { return AcquireRegisterOfSize(reg.GetSizeInBits()); } VRegister AcquireVRegisterOfSize(int size_in_bits); VRegister AcquireSameSizeAs(const VRegister& reg) { return AcquireVRegisterOfSize(reg.GetSizeInBits()); } CPURegister AcquireCPURegisterOfSize(int size_in_bits) { return masm_->GetScratchRegisterList()->IsEmpty() ? CPURegister(AcquireVRegisterOfSize(size_in_bits)) : CPURegister(AcquireRegisterOfSize(size_in_bits)); } // Acquire a register big enough to represent one lane of `vector`. Register AcquireRegisterToHoldLane(const CPURegister& vector) { VIXL_ASSERT(vector.GetLaneSizeInBits() <= kXRegSize); return (vector.GetLaneSizeInBits() > kWRegSize) ? AcquireX() : AcquireW(); } // Explicitly release an acquired (or excluded) register, putting it back in // the appropriate temps list. void Release(const CPURegister& reg); // Make the specified registers available as scratch registers for the // duration of this scope. void Include(const CPURegList& list); void Include(const Register& reg1, const Register& reg2 = NoReg, const Register& reg3 = NoReg, const Register& reg4 = NoReg); void Include(const VRegister& reg1, const VRegister& reg2 = NoVReg, const VRegister& reg3 = NoVReg, const VRegister& reg4 = NoVReg); void Include(const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg, const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg); // Make sure that the specified registers are not available in this scope. // This can be used to prevent helper functions from using sensitive // registers, for example. void Exclude(const CPURegList& list); void Exclude(const Register& reg1, const Register& reg2 = NoReg, const Register& reg3 = NoReg, const Register& reg4 = NoReg); void Exclude(const VRegister& reg1, const VRegister& reg2 = NoVReg, const VRegister& reg3 = NoVReg, const VRegister& reg4 = NoVReg); void Exclude(const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg, const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg); // Convenience for excluding registers that are part of Operands. This is // useful for sequences like this: // // // Use 'rd' as a scratch, but only if it's not aliased by an input. // temps.Include(rd); // temps.Exclude(rn); // temps.Exclude(operand); // // Otherwise, a conditional check is needed on the last 'Exclude'. void Exclude(const Operand& operand) { if (operand.IsShiftedRegister() || operand.IsExtendedRegister()) { Exclude(operand.GetRegister()); } else { VIXL_ASSERT(operand.IsImmediate()); } } // Prevent any scratch registers from being used in this scope. void ExcludeAll(); private: static CPURegister AcquireFrom(CPURegList* available, RegList mask = ~static_cast(0)); static void ReleaseByCode(CPURegList* available, int code); static void ReleaseByRegList(CPURegList* available, RegList regs); static void IncludeByRegList(CPURegList* available, RegList exclude); static void ExcludeByRegList(CPURegList* available, RegList exclude); CPURegList* GetAvailableListFor(CPURegister::RegisterBank bank); static const RegList kGoverningPRegisterMask = (static_cast(1) << kNumberOfGoverningPRegisters) - 1; // The MacroAssembler maintains a list of available scratch registers, and // also keeps track of the most recently-opened scope so that on destruction // we can check that scopes do not outlive their parents. MacroAssembler* masm_; UseScratchRegisterScope* parent_; // The state of the available lists at the start of this scope. RegList old_available_; // kRegister RegList old_available_v_; // kVRegister / kZRegister RegList old_available_p_; // kPRegister // Disallow copy constructor and operator=. VIXL_NO_RETURN_IN_DEBUG_MODE UseScratchRegisterScope( const UseScratchRegisterScope&) { VIXL_UNREACHABLE(); } VIXL_NO_RETURN_IN_DEBUG_MODE void operator=(const UseScratchRegisterScope&) { VIXL_UNREACHABLE(); } }; // Like CPUFeaturesScope, but also generate Simulation pseudo-instructions to // control a Simulator's CPUFeatures dynamically. // // One major difference from CPUFeaturesScope is that this scope cannot offer // a writable "CPUFeatures* GetCPUFeatures()", because every write to the // features needs a corresponding macro instruction. class SimulationCPUFeaturesScope { public: template explicit SimulationCPUFeaturesScope(MacroAssembler* masm, T... features) : masm_(masm), cpu_features_scope_(masm, features...) { masm_->SaveSimulatorCPUFeatures(); masm_->EnableSimulatorCPUFeatures(CPUFeatures(features...)); } ~SimulationCPUFeaturesScope() { masm_->RestoreSimulatorCPUFeatures(); } const CPUFeatures* GetCPUFeatures() const { return cpu_features_scope_.GetCPUFeatures(); } void SetCPUFeatures(const CPUFeatures& cpu_features) { cpu_features_scope_.SetCPUFeatures(cpu_features); masm_->SetSimulatorCPUFeatures(cpu_features); } private: MacroAssembler* masm_; CPUFeaturesScope cpu_features_scope_; }; // Variadic templating is only available from C++11. #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT // `R` stands for 'return type', and `P` for 'parameter types'. template void MacroAssembler::CallRuntimeHelper(R (*function)(P...), RuntimeCallType call_type) { if (generate_simulator_code_) { #ifdef VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT uintptr_t runtime_call_wrapper_address = reinterpret_cast( &(Simulator::RuntimeCallStructHelper::Wrapper)); uintptr_t function_address = reinterpret_cast(function); EmissionCheckScope guard(this, kRuntimeCallLength, CodeBufferCheckScope::kExactSize); Label start; bind(&start); { ExactAssemblyScope scope(this, kInstructionSize); hlt(kRuntimeCallOpcode); } VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kRuntimeCallWrapperOffset); dc(runtime_call_wrapper_address); VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kRuntimeCallFunctionOffset); dc(function_address); VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kRuntimeCallTypeOffset); dc32(call_type); VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kRuntimeCallLength); #else VIXL_UNREACHABLE(); #endif // #ifdef VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT } else { UseScratchRegisterScope temps(this); Register temp = temps.AcquireX(); Mov(temp, reinterpret_cast(function)); if (call_type == kTailCallRuntime) { Br(temp); } else { VIXL_ASSERT(call_type == kCallRuntime); Blr(temp); } } } #endif // #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT } // namespace aarch64 // Required InvalSet template specialisations. // TODO: These template specialisations should not live in this file. Move // VeneerPool out of the aarch64 namespace in order to share its implementation // later. template <> inline ptrdiff_t InvalSet:: GetKey(const aarch64::VeneerPool::BranchInfo& branch_info) { return branch_info.first_unreacheable_pc_; } template <> inline void InvalSet:: SetKey(aarch64::VeneerPool::BranchInfo* branch_info, ptrdiff_t key) { branch_info->first_unreacheable_pc_ = key; } } // namespace vixl #endif // VIXL_AARCH64_MACRO_ASSEMBLER_AARCH64_H_