// 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.
// Some CPURegister methods can return Register or VRegister types, so we need // to declare them in advance. classRegister; class VRegister;
class CPURegister { public: enum RegisterType { // The kInvalid value is used to detect uninitialized static instances, // which are always zero-initialized before any constructors are called.
kInvalid = 0,
kRegister,
kVRegister,
kFPRegister = kVRegister,
kNoRegister
};
bool IsValid() const { if (IsValidRegister() || IsValidVRegister()) {
VIXL_ASSERT(!IsNone()); returntrue;
} else { // This assert is hit when the register has not been properly initialized. // One cause for this can be an initialisation order fiasco. See // https://isocpp.org/wiki/faq/ctors#static-init-order for some details.
VIXL_ASSERT(IsNone()); returnfalse;
}
}
// These assertions ensure that the size and type of the register are as // described. They do not consider the number of lanes that make up a vector. // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() // does not imply Is1D() or Is8B(). // Check the number of lanes, ie. the format of the vector, using methods such // as Is8B(), Is1D(), etc. in the VRegister class. bool IsV() const { return IsVRegister(); } bool IsB() const { return IsV() && Is8Bits(); } bool IsH() const { return IsV() && Is16Bits(); } bool IsS() const { return IsV() && Is32Bits(); } bool IsD() const { return IsV() && Is64Bits(); } bool IsQ() const { return IsV() && Is128Bits(); }
js::jit::Register asUnsized() const { // asUnsized() is only ever used on temp registers or on registers that // are known not to be SP, and there should be no risk of it being // applied to SP. Check anyway.
VIXL_ASSERT(code_ != kSPRegInternalCode); return js::jit::Register::FromCode((js::jit::Register::Code)code_);
}
// For consistency, we assert the number of lanes of these scalar registers, // even though there are no vectors of equivalent total size with which they // could alias. bool Is1B() const {
VIXL_ASSERT(!(Is8Bits() && IsVector())); return Is8Bits();
} bool Is1H() const {
VIXL_ASSERT(!(Is16Bits() && IsVector())); return Is16Bits();
} bool Is1S() const {
VIXL_ASSERT(!(Is32Bits() && IsVector())); return Is32Bits();
}
// Backward compatibility for FPRegisters. typedef VRegister FPRegister;
// No*Reg is used to indicate an unused argument, or an error case. Note that // these all compare equal (using the Is() method). The Register and VRegister // variants are provided for convenience. constRegister NoReg; const VRegister NoVReg; const FPRegister NoFPReg; // For backward compatibility. const CPURegister NoCPUReg;
// AreAliased returns true if any of the named registers overlap. Arguments // set to NoReg are ignored. The system stack pointer may be specified. bool AreAliased(const CPURegister& reg1, const CPURegister& reg2, const CPURegister& reg3 = NoReg, const CPURegister& reg4 = NoReg, const CPURegister& reg5 = NoReg, const CPURegister& reg6 = NoReg, const CPURegister& reg7 = NoReg, const CPURegister& reg8 = NoReg);
// AreSameSizeAndType returns true if all of the specified registers have the // same size, and are of the same type. The system stack pointer may be // specified. Arguments set to NoReg are ignored, as are any subsequent // arguments. At least one argument (reg1) must be valid (not NoCPUReg). bool AreSameSizeAndType(const CPURegister& reg1, const CPURegister& reg2, const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg, const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg, const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg);
// AreEven returns true if all of the specified registers have even register // indices. Arguments set to NoReg are ignored, as are any subsequent // arguments. At least one argument (reg1) must be valid (not NoCPUReg). bool AreEven(const CPURegister& reg1, const CPURegister& reg2, const CPURegister& reg3 = NoReg, const CPURegister& reg4 = NoReg, const CPURegister& reg5 = NoReg, const CPURegister& reg6 = NoReg, const CPURegister& reg7 = NoReg, const CPURegister& reg8 = NoReg);
// AreConsecutive returns true if all of the specified registers are // consecutive in the register file. Arguments set to NoReg are ignored, as are // any subsequent arguments. At least one argument (reg1) must be valid // (not NoCPUReg). bool AreConsecutive(const CPURegister& reg1, const CPURegister& reg2, const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg);
// AreSameFormat returns true if all of the specified VRegisters have the same // vector format. Arguments set to NoReg are ignored, as are any subsequent // arguments. At least one argument (reg1) must be valid (not NoVReg). bool AreSameFormat(const VRegister& reg1, const VRegister& reg2, const VRegister& reg3 = NoVReg, const VRegister& reg4 = NoVReg);
// AreConsecutive returns true if all of the specified VRegisters are // consecutive in the register file. Arguments set to NoReg are ignored, as are // any subsequent arguments. At least one argument (reg1) must be valid // (not NoVReg). bool AreConsecutive(const VRegister& reg1, const VRegister& reg2, const VRegister& reg3 = NoVReg, const VRegister& reg4 = NoVReg);
// Combine another CPURegList into this one. Registers that already exist in // this list are left unchanged. The type and size of the registers in the // 'other' list must match those in this list. void Combine(const CPURegList& other) {
VIXL_ASSERT(IsValid());
VIXL_ASSERT(other.type() == type_);
VIXL_ASSERT(other.RegisterSizeInBits() == size_);
list_ |= other.list();
}
// Remove every register in the other CPURegList from this one. Registers that // do not exist in this list are ignored. The type and size of the registers // in the 'other' list must match those in this list. void Remove(const CPURegList& other) {
VIXL_ASSERT(IsValid());
VIXL_ASSERT(other.type() == type_);
VIXL_ASSERT(other.RegisterSizeInBits() == size_);
list_ &= ~other.list();
}
// Variants of Combine and Remove which take a single register. void Combine(const CPURegister& other) {
VIXL_ASSERT(other.type() == type_);
VIXL_ASSERT(other.size() == size_);
Combine(other.code());
}
// Variants of Combine and Remove which take a single register by its code; // the type and size of the register is inferred from this list. void Combine(int code) {
VIXL_ASSERT(IsValid());
VIXL_ASSERT(CPURegister(code, size_, type_).IsValid());
list_ |= (UINT64_C(1) << code);
}
// Remove all callee-saved registers from the list. This can be useful when // preparing registers for an AAPCS64 function call, for example. void RemoveCalleeSaved();
// AAPCS64 caller-saved registers. Note that this includes lr. // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top // 64-bits being caller-saved. static CPURegList GetCallerSaved(unsigned size = kXRegSize); static CPURegList GetCallerSavedV(unsigned size = kDRegSize);
// AAPCS64 caller-saved registers. Note that this includes lr. externconst CPURegList kCallerSaved; externconst CPURegList kCallerSavedV;
// Operand. class Operand { public: // #<immediate> // where <immediate> is int64_t. // This is allowed to be an implicit constructor because Operand is // a wrapper class that doesn't normally perform any type conversion.
Operand(int64_t immediate = 0); // NOLINT(runtime/explicit)
// rm, {<shift> #<shift_amount>} // where <shift> is one of {LSL, LSR, ASR, ROR}. // <shift_amount> is uint6_t. // This is allowed to be an implicit constructor because Operand is // a wrapper class that doesn't normally perform any type conversion.
Operand(Register reg,
Shift shift = LSL, unsigned shift_amount = 0); // NOLINT(runtime/explicit)
// rm, {<extend> {#<shift_amount>}} // where <extend> is one of {UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX}. // <shift_amount> is uint2_t. explicit Operand(Register reg, Extend extend, unsigned shift_amount = 0);
// This returns an LSL shift (<= 4) operand as an equivalent extend operand, // which helps in the encoding of instructions that use the stack pointer.
Operand ToExtendedRegister() const;
// Control whether or not position-independent code should be emitted. enum PositionIndependentCodeOption { // All code generated will be position-independent; all branches and // references to labels generated with the Label class will use PC-relative // addressing.
PositionIndependentCode,
// Allow VIXL to generate code that refers to absolute addresses. With this // option, it will not be possible to copy the code buffer and run it from a // different address; code must be generated in its final location.
PositionDependentCode,
// Allow VIXL to assume that the bottom 12 bits of the address will be // constant, but that the top 48 bits may change. This allows `adrp` to // function in systems which copy code between pages, but otherwise maintain // 4KB page alignment.
PageOffsetDependentCode
};
// Control how scaled- and unscaled-offset loads and stores are generated. enum LoadStoreScalingOption { // Prefer scaled-immediate-offset instructions, but emit unscaled-offset, // register-offset, pre-index or post-index instructions if necessary.
PreferScaledOffset,
// Prefer unscaled-immediate-offset instructions, but emit scaled-offset, // register-offset, pre-index or post-index instructions if necessary.
PreferUnscaledOffset,
// Assembler. class Assembler : public MozBaseAssembler { public:
Assembler(PositionIndependentCodeOption pic = PositionIndependentCode);
// System functions.
// Finalize a code buffer of generated instructions. This function must be // called before executing or copying code from the buffer. void FinalizeCode();
// Bit set when a DoubleCondition does not map to a single ARM condition. // The MacroAssembler must special-case these conditions, or else // ConditionFromDoubleCondition will complain. staticconstint DoubleConditionBitSpecial = 0x100;
// If either operand is NaN, these conditions always evaluate to true.
DoubleUnordered = Condition::vs,
DoubleEqualOrUnordered = Condition::eq | DoubleConditionBitSpecial,
DoubleNotEqualOrUnordered = Condition::ne,
DoubleGreaterThanOrUnordered = Condition::hi,
DoubleGreaterThanOrEqualOrUnordered = Condition::hs,
DoubleLessThanOrUnordered = Condition::lt,
DoubleLessThanOrEqualOrUnordered = Condition::le
};
staticinline Condition InvertCondition(Condition cond) { // Conditions al and nv behave identically, as "always true". They can't be // inverted, because there is no "always false" condition.
VIXL_ASSERT((cond != al) && (cond != nv)); returnstatic_cast<Condition>(cond ^ 1);
}
// This is chaging the condition codes for cmp a, b to the same codes for cmp b, a. staticinline Condition InvertCmpCondition(Condition cond) { // Conditions al and nv behave identically, as "always true". They can't be // inverted, because there is no "always false" condition. switch (cond) { case eq: case ne: return cond; case gt: return le; case le: return gt; case ge: return lt; case lt: return ge; case hi: return lo; case lo: return hi; case hs: return ls; case ls: return hs; case mi: return pl; case pl: return mi; default:
MOZ_CRASH("TODO: figure this case out.");
} returnstatic_cast<Condition>(cond ^ 1);
}
staticinline DoubleCondition InvertCondition(DoubleCondition cond) { switch (cond) { case DoubleOrdered: return DoubleUnordered; case DoubleEqual: return DoubleNotEqualOrUnordered; case DoubleNotEqual: return DoubleEqualOrUnordered; case DoubleGreaterThan: return DoubleLessThanOrEqualOrUnordered; case DoubleGreaterThanOrEqual: return DoubleLessThanOrUnordered; case DoubleLessThan: return DoubleGreaterThanOrEqualOrUnordered; case DoubleLessThanOrEqual: return DoubleGreaterThanOrUnordered; case DoubleUnordered: return DoubleOrdered; case DoubleEqualOrUnordered: return DoubleNotEqual; case DoubleNotEqualOrUnordered: return DoubleEqual; case DoubleGreaterThanOrUnordered: return DoubleLessThanOrEqual; case DoubleGreaterThanOrEqualOrUnordered: return DoubleLessThan; case DoubleLessThanOrUnordered: return DoubleGreaterThanOrEqual; case DoubleLessThanOrEqualOrUnordered: return DoubleGreaterThan; default:
MOZ_CRASH("Bad condition");
}
}
// Branch with link to register. void blr(constRegister& xn); staticvoid blr(Instruction* at, constRegister& blr);
// Branch to register with return hint. void ret(constRegister& xn = lr);
// Unconditional branch to label.
BufferOffset b(Label* label);
// Conditional branch to label.
BufferOffset b(Label* label, Condition cond);
// Unconditional branch to PC offset.
BufferOffset b(int imm26, const LabelDoc& doc); staticvoid b(Instruction* at, int imm26);
// Conditional branch to PC offset.
BufferOffset b(int imm19, Condition cond, const LabelDoc& doc); staticvoid b(Instruction*at, int imm19, Condition cond);
// Branch with link to label. void bl(Label* label);
// Branch with link to PC offset. void bl(int imm26, const LabelDoc& doc); staticvoid bl(Instruction* at, int imm26);
// Compare and branch to label if zero. void cbz(constRegister& rt, Label* label);
// Compare and branch to PC offset if zero. void cbz(constRegister& rt, int imm19, const LabelDoc& doc); staticvoid cbz(Instruction* at, constRegister& rt, int imm19);
// Compare and branch to label if not zero. void cbnz(constRegister& rt, Label* label);
// Compare and branch to PC offset if not zero. void cbnz(constRegister& rt, int imm19, const LabelDoc& doc); staticvoid cbnz(Instruction* at, constRegister& rt, int imm19);
// Table lookup from one register. void tbl(const VRegister& vd, const VRegister& vn, const VRegister& vm);
// Table lookup from two registers. void tbl(const VRegister& vd, const VRegister& vn, const VRegister& vn2, const VRegister& vm);
// Test bit and branch to label if zero. void tbz(constRegister& rt, unsigned bit_pos, Label* label);
// Test bit and branch to PC offset if zero. void tbz(constRegister& rt, unsigned bit_pos, int imm14, const LabelDoc& doc); staticvoid tbz(Instruction* at, constRegister& rt, unsigned bit_pos, int imm14);
// Test bit and branch to label if not zero. void tbnz(constRegister& rt, unsigned bit_pos, Label* label);
// Test bit and branch to PC offset if not zero. void tbnz(constRegister& rt, unsigned bit_pos, int imm14, const LabelDoc& doc); staticvoid tbnz(Instruction* at, constRegister& rt, unsigned bit_pos, int imm14);
// Address calculation instructions. // Calculate a PC-relative address. Unlike for branches the offset in adr is // unscaled (i.e. the result can be unaligned).
// Calculate the address of a label. void adr(constRegister& rd, Label* label);
// Calculate the address of a PC offset. void adr(constRegister& rd, int imm21, const LabelDoc& doc); staticvoid adr(Instruction* at, constRegister& rd, int imm21);
// Calculate the page address of a label. void adrp(constRegister& rd, Label* label);
// Calculate the page address of a PC offset. void adrp(constRegister& rd, int imm21, const LabelDoc& doc); staticvoid adrp(Instruction* at, constRegister& rd, int imm21);
// Store integer or FP register pair, non-temporal. void stnp(const CPURegister& rt, const CPURegister& rt2, const MemOperand& dst);
// Load integer or FP register from pc + imm19 << 2. void ldr(const CPURegister& rt, int imm19); staticvoid ldr(Instruction* at, const CPURegister& rt, int imm19);
// Load word with sign extension from pc + imm19 << 2. void ldrsw(constRegister& rt, int imm19); staticvoid ldrsw(Instruction* at, const CPURegister& rt, int imm19);
// Compare and Swap word or doubleword in memory [Armv8.1]. void cas(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap word or doubleword in memory [Armv8.1]. void casa(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap word or doubleword in memory [Armv8.1]. void casl(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap word or doubleword in memory [Armv8.1]. void casal(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap byte in memory [Armv8.1]. void casb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap byte in memory [Armv8.1]. void casab(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap byte in memory [Armv8.1]. void caslb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap byte in memory [Armv8.1]. void casalb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap halfword in memory [Armv8.1]. void cash(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap halfword in memory [Armv8.1]. void casah(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap halfword in memory [Armv8.1]. void caslh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap halfword in memory [Armv8.1]. void casalh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Compare and Swap Pair of words or doublewords in memory [Armv8.1]. void casp(constRegister& rs, constRegister& rs2, constRegister& rt, constRegister& rt2, const MemOperand& src);
// Compare and Swap Pair of words or doublewords in memory [Armv8.1]. void caspa(constRegister& rs, constRegister& rs2, constRegister& rt, constRegister& rt2, const MemOperand& src);
// Compare and Swap Pair of words or doublewords in memory [Armv8.1]. void caspl(constRegister& rs, constRegister& rs2, constRegister& rt, constRegister& rt2, const MemOperand& src);
// Compare and Swap Pair of words or doublewords in memory [Armv8.1]. void caspal(constRegister& rs, constRegister& rs2, constRegister& rt, constRegister& rt2, const MemOperand& src);
// Atomic add on byte in memory [Armv8.1] void ldaddb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on byte in memory, with Load-acquire semantics [Armv8.1] void ldaddab(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on byte in memory, with Store-release semantics [Armv8.1] void ldaddlb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on byte in memory, with Load-acquire and Store-release semantics // [Armv8.1] void ldaddalb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on halfword in memory [Armv8.1] void ldaddh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on halfword in memory, with Load-acquire semantics [Armv8.1] void ldaddah(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on halfword in memory, with Store-release semantics [Armv8.1] void ldaddlh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on halfword in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldaddalh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on word or doubleword in memory [Armv8.1] void ldadd(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on word or doubleword in memory, with Load-acquire semantics // [Armv8.1] void ldadda(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on word or doubleword in memory, with Store-release semantics // [Armv8.1] void ldaddl(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic add on word or doubleword in memory, with Load-acquire and // Store-release semantics [Armv8.1] void ldaddal(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on byte in memory [Armv8.1] void ldclrb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on byte in memory, with Load-acquire semantics [Armv8.1] void ldclrab(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on byte in memory, with Store-release semantics [Armv8.1] void ldclrlb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on byte in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldclralb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on halfword in memory [Armv8.1] void ldclrh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on halfword in memory, with Load-acquire semantics // [Armv8.1] void ldclrah(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on halfword in memory, with Store-release semantics // [Armv8.1] void ldclrlh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on halfword in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldclralh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on word or doubleword in memory [Armv8.1] void ldclr(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on word or doubleword in memory, with Load-acquire // semantics [Armv8.1] void ldclra(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on word or doubleword in memory, with Store-release // semantics [Armv8.1] void ldclrl(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit clear on word or doubleword in memory, with Load-acquire and // Store-release semantics [Armv8.1] void ldclral(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on byte in memory [Armv8.1] void ldeorb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on byte in memory, with Load-acquire semantics // [Armv8.1] void ldeorab(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on byte in memory, with Store-release semantics // [Armv8.1] void ldeorlb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on byte in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldeoralb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on halfword in memory [Armv8.1] void ldeorh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on halfword in memory, with Load-acquire semantics // [Armv8.1] void ldeorah(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on halfword in memory, with Store-release semantics // [Armv8.1] void ldeorlh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on halfword in memory, with Load-acquire and // Store-release semantics [Armv8.1] void ldeoralh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on word or doubleword in memory [Armv8.1] void ldeor(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on word or doubleword in memory, with Load-acquire // semantics [Armv8.1] void ldeora(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on word or doubleword in memory, with Store-release // semantics [Armv8.1] void ldeorl(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic exclusive OR on word or doubleword in memory, with Load-acquire and // Store-release semantics [Armv8.1] void ldeoral(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on byte in memory [Armv8.1] void ldsetb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on byte in memory, with Load-acquire semantics [Armv8.1] void ldsetab(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on byte in memory, with Store-release semantics [Armv8.1] void ldsetlb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on byte in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldsetalb(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on halfword in memory [Armv8.1] void ldseth(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on halfword in memory, with Load-acquire semantics [Armv8.1] void ldsetah(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on halfword in memory, with Store-release semantics // [Armv8.1] void ldsetlh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on halfword in memory, with Load-acquire and Store-release // semantics [Armv8.1] void ldsetalh(constRegister& rs, constRegister& rt, const MemOperand& src);
// Atomic bit set on word or doubleword in memory [Armv8.1]
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.60 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.