Issue #3049 - Enable loongarch64 JIT atomics

This commit is contained in:
Basilisk-Dev 2026-04-24 21:02:04 -04:00 committed by wuggy
commit 4c58aa2724
3 changed files with 699 additions and 16 deletions

View file

@ -306,58 +306,307 @@ CodeGeneratorLoongArch64::visitWasmAddOffset(LWasmAddOffset* lir)
masm.branchPtr(Assembler::Below, out, limitBase, trap(mir, wasm::Trap::OutOfBounds));
}
template <typename S, typename T>
static void
AtomicBinopToTypedIntArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op,
Scalar::Type arrayType, const S& value,
const T& mem, Register outTemp,
Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
masm.atomicFetchOp(1, true, op, value, mem, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint8:
masm.atomicFetchOp(1, false, op, value, mem, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int16:
masm.atomicFetchOp(2, true, op, value, mem, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint16:
masm.atomicFetchOp(2, false, op, value, mem, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int32:
masm.atomicFetchOp(4, false, op, value, mem, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint32:
MOZ_ASSERT(output.isFloat());
MOZ_ASSERT(outTemp != InvalidReg);
masm.atomicFetchOp(4, false, op, value, mem, valueTemp, offsetTemp,
maskTemp, outTemp);
masm.convertUInt32ToDouble(outTemp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template <typename S, typename T>
static void
AtomicBinopToTypedIntArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op,
Scalar::Type arrayType, const S& value,
const T& mem, Register valueTemp,
Register offsetTemp, Register maskTemp)
{
switch (arrayType) {
case Scalar::Int8:
case Scalar::Uint8:
masm.atomicEffectOp(1, op, value, mem, valueTemp, offsetTemp,
maskTemp);
break;
case Scalar::Int16:
case Scalar::Uint16:
masm.atomicEffectOp(2, op, value, mem, valueTemp, offsetTemp,
maskTemp);
break;
case Scalar::Int32:
case Scalar::Uint32:
masm.atomicEffectOp(4, op, value, mem, valueTemp, offsetTemp,
maskTemp);
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template <typename T>
static void
AtomicBinopToTypedArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op,
Scalar::Type arrayType, const LAllocation* value,
const T& mem, Register outTemp, Register valueTemp,
Register offsetTemp, Register maskTemp,
AnyRegister output)
{
if (value->isConstant()) {
AtomicBinopToTypedIntArray(masm, op, arrayType, Imm32(ToInt32(value)),
mem, outTemp, valueTemp, offsetTemp,
maskTemp, output);
} else {
AtomicBinopToTypedIntArray(masm, op, arrayType, ToRegister(value),
mem, outTemp, valueTemp, offsetTemp,
maskTemp, output);
}
}
template <typename T>
static void
AtomicBinopToTypedArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op,
Scalar::Type arrayType, const LAllocation* value,
const T& mem, Register valueTemp, Register offsetTemp,
Register maskTemp)
{
if (value->isConstant()) {
AtomicBinopToTypedIntArray(masm, op, arrayType, Imm32(ToInt32(value)),
mem, valueTemp, offsetTemp, maskTemp);
} else {
AtomicBinopToTypedIntArray(masm, op, arrayType, ToRegister(value),
mem, valueTemp, offsetTemp, maskTemp);
}
}
void
CodeGeneratorLoongArch64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
{
(void)ins;
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
MAsmJSCompareExchangeHeap* mir = ins->mir();
Scalar::Type vt = mir->access().type();
Register ptrReg = ToRegister(ins->ptr());
BaseIndex srcAddr(HeapReg, ptrReg, TimesOne);
MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
Register oldval = ToRegister(ins->oldValue());
Register newval = ToRegister(ins->newValue());
Register valueTemp = ToRegister(ins->valueTemp());
Register offsetTemp = ToRegister(ins->offsetTemp());
Register maskTemp = ToRegister(ins->maskTemp());
masm.compareExchangeToTypedIntArray(
vt == Scalar::Uint32 ? Scalar::Int32 : vt, srcAddr, oldval, newval,
InvalidReg, valueTemp, offsetTemp, maskTemp,
ToAnyRegister(ins->output()));
}
void
CodeGeneratorLoongArch64::visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins)
{
(void)ins;
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
MAsmJSAtomicExchangeHeap* mir = ins->mir();
Scalar::Type vt = mir->access().type();
Register ptrReg = ToRegister(ins->ptr());
Register value = ToRegister(ins->value());
BaseIndex srcAddr(HeapReg, ptrReg, TimesOne);
MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
Register valueTemp = ToRegister(ins->valueTemp());
Register offsetTemp = ToRegister(ins->offsetTemp());
Register maskTemp = ToRegister(ins->maskTemp());
masm.atomicExchangeToTypedIntArray(
vt == Scalar::Uint32 ? Scalar::Int32 : vt, srcAddr, value, InvalidReg,
valueTemp, offsetTemp, maskTemp, ToAnyRegister(ins->output()));
}
void
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
{
(void)ins;
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
MOZ_ASSERT(ins->mir()->hasUses());
MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
MAsmJSAtomicBinopHeap* mir = ins->mir();
Scalar::Type vt = mir->access().type();
Register ptrReg = ToRegister(ins->ptr());
Register valueTemp = ToRegister(ins->valueTemp());
Register offsetTemp = ToRegister(ins->offsetTemp());
Register maskTemp = ToRegister(ins->maskTemp());
const LAllocation* value = ins->value();
AtomicOp op = mir->operation();
BaseIndex srcAddr(HeapReg, ptrReg, TimesOne);
AtomicBinopToTypedArray(masm, op,
vt == Scalar::Uint32 ? Scalar::Int32 : vt, value,
srcAddr, InvalidReg, valueTemp, offsetTemp,
maskTemp, ToAnyRegister(ins->output()));
}
void
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins)
{
(void)ins;
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
MOZ_ASSERT(!ins->mir()->hasUses());
MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
MAsmJSAtomicBinopHeap* mir = ins->mir();
Scalar::Type vt = mir->access().type();
Register ptrReg = ToRegister(ins->ptr());
Register valueTemp = ToRegister(ins->valueTemp());
Register offsetTemp = ToRegister(ins->offsetTemp());
Register maskTemp = ToRegister(ins->maskTemp());
const LAllocation* value = ins->value();
AtomicOp op = mir->operation();
BaseIndex srcAddr(HeapReg, ptrReg, TimesOne);
AtomicBinopToTypedArray(masm, op, vt, value, srcAddr, valueTemp,
offsetTemp, maskTemp);
}
void
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir)
{
(void)lir;
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
MOZ_ASSERT(lir->mir()->hasUses());
AnyRegister output = ToAnyRegister(lir->output());
Register elements = ToRegister(lir->elements());
Register outTemp = lir->temp2()->isBogusTemp() ? InvalidReg
: ToRegister(lir->temp2());
Register valueTemp = ToRegister(lir->valueTemp());
Register offsetTemp = ToRegister(lir->offsetTemp());
Register maskTemp = ToRegister(lir->maskTemp());
const LAllocation* value = lir->value();
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address mem(elements, ToInt32(lir->index()) * width);
AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value,
mem, outTemp, valueTemp, offsetTemp, maskTemp,
output);
} else {
BaseIndex mem(elements, ToRegister(lir->index()),
ScaleFromElemWidth(width));
AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value,
mem, outTemp, valueTemp, offsetTemp, maskTemp,
output);
}
}
void
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir)
{
(void)lir;
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
MOZ_ASSERT(!lir->mir()->hasUses());
Register elements = ToRegister(lir->elements());
Register valueTemp = ToRegister(lir->valueTemp());
Register offsetTemp = ToRegister(lir->offsetTemp());
Register maskTemp = ToRegister(lir->maskTemp());
const LAllocation* value = lir->value();
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address mem(elements, ToInt32(lir->index()) * width);
AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value,
mem, valueTemp, offsetTemp, maskTemp);
} else {
BaseIndex mem(elements, ToRegister(lir->index()),
ScaleFromElemWidth(width));
AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value,
mem, valueTemp, offsetTemp, maskTemp);
}
}
void
CodeGeneratorLoongArch64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
{
(void)lir;
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg
: ToRegister(lir->temp());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Register valueTemp = ToRegister(lir->valueTemp());
Register offsetTemp = ToRegister(lir->offsetTemp());
Register maskTemp = ToRegister(lir->maskTemp());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval,
temp, valueTemp, offsetTemp,
maskTemp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromElemWidth(width));
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval,
temp, valueTemp, offsetTemp,
maskTemp, output);
}
}
void
CodeGeneratorLoongArch64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
{
(void)lir;
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg
: ToRegister(lir->temp());
Register value = ToRegister(lir->value());
Register valueTemp = ToRegister(lir->valueTemp());
Register offsetTemp = ToRegister(lir->offsetTemp());
Register maskTemp = ToRegister(lir->maskTemp());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp,
valueTemp, offsetTemp, maskTemp,
output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromElemWidth(width));
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp,
valueTemp, offsetTemp, maskTemp,
output);
}
}

View file

@ -22,6 +22,140 @@
namespace js {
namespace jit {
namespace {
static inline void MoveAtomicValue(MacroAssemblerLOONGARCH64Compat& masm,
Imm32 value, Register dest) {
masm.move32(value, dest);
}
static inline void MoveAtomicValue(MacroAssemblerLOONGARCH64Compat& masm,
Register value, Register dest) {
masm.move32(value, dest);
}
static inline void SignExtendAtomicResult(MacroAssemblerLOONGARCH64Compat& masm,
int nbytes, Register output) {
switch (nbytes) {
case 1:
masm.as_ext_w_b(output, output);
break;
case 2:
masm.as_ext_w_h(output, output);
break;
case 4:
break;
default:
MOZ_CRASH("unexpected atomic width");
}
}
template <typename T>
static inline void PrepareAtomicAddress(
MacroAssemblerLOONGARCH64Compat& masm, int nbytes, const T& address,
Register offsetTemp, Register maskTemp) {
masm.computeEffectiveAddress(address, ScratchRegister);
masm.as_andi(offsetTemp, ScratchRegister, 3);
masm.as_sub_d(ScratchRegister, ScratchRegister, offsetTemp);
masm.as_slli_w(offsetTemp, offsetTemp, 3);
masm.ma_li(maskTemp, Imm32(int32_t(UINT32_MAX >> ((4 - nbytes) * 8))));
masm.as_sll_w(maskTemp, maskTemp, offsetTemp);
}
template <typename S, typename T>
static void AtomicFetchOpLoongArch64(MacroAssemblerLOONGARCH64Compat& masm,
int nbytes, bool signExtend, AtomicOp op,
const S& value, const T& address,
Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
Label again;
PrepareAtomicAddress(masm, nbytes, address, offsetTemp, maskTemp);
masm.bind(&again);
masm.as_dbar(0);
masm.as_ll_w(SecondScratchReg, ScratchRegister, 0);
if (output != InvalidReg) {
masm.as_and(output, SecondScratchReg, maskTemp);
masm.as_srl_w(output, output, offsetTemp);
if (signExtend) {
SignExtendAtomicResult(masm, nbytes, output);
}
}
MoveAtomicValue(masm, value, valueTemp);
masm.as_sll_w(valueTemp, valueTemp, offsetTemp);
switch (op) {
case AtomicFetchAddOp:
masm.as_add_w(valueTemp, SecondScratchReg, valueTemp);
break;
case AtomicFetchSubOp:
masm.as_sub_w(valueTemp, SecondScratchReg, valueTemp);
break;
case AtomicFetchAndOp:
masm.as_and(valueTemp, SecondScratchReg, valueTemp);
break;
case AtomicFetchOrOp:
masm.as_or(valueTemp, SecondScratchReg, valueTemp);
break;
case AtomicFetchXorOp:
masm.as_xor(valueTemp, SecondScratchReg, valueTemp);
break;
default:
MOZ_CRASH("unexpected atomic op");
}
masm.as_and(valueTemp, valueTemp, maskTemp);
masm.as_or(SecondScratchReg, SecondScratchReg, maskTemp);
masm.as_xor(SecondScratchReg, SecondScratchReg, maskTemp);
masm.as_or(SecondScratchReg, SecondScratchReg, valueTemp);
masm.as_sc_w(SecondScratchReg, ScratchRegister, 0);
masm.ma_b(SecondScratchReg, SecondScratchReg, &again, Assembler::Zero,
ShortJump);
masm.as_dbar(0);
}
template <typename T>
static void CompareExchangeLoongArch64(
MacroAssemblerLOONGARCH64Compat& masm, int nbytes, bool signExtend,
const T& address, Register oldval, Register newval, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output) {
Label again, done;
PrepareAtomicAddress(masm, nbytes, address, offsetTemp, maskTemp);
masm.bind(&again);
masm.as_dbar(0);
masm.as_ll_w(SecondScratchReg, ScratchRegister, 0);
masm.as_and(output, SecondScratchReg, maskTemp);
masm.as_srl_w(output, output, offsetTemp);
if (signExtend) {
SignExtendAtomicResult(masm, nbytes, output);
}
if (oldval != InvalidReg) {
masm.ma_b(output, oldval, &done, Assembler::NotEqual, ShortJump);
}
masm.move32(newval, valueTemp);
masm.as_sll_w(valueTemp, valueTemp, offsetTemp);
masm.as_and(valueTemp, valueTemp, maskTemp);
masm.as_or(SecondScratchReg, SecondScratchReg, maskTemp);
masm.as_xor(SecondScratchReg, SecondScratchReg, maskTemp);
masm.as_or(SecondScratchReg, SecondScratchReg, valueTemp);
masm.as_sc_w(SecondScratchReg, ScratchRegister, 0);
masm.ma_b(SecondScratchReg, SecondScratchReg, &again, Assembler::Zero,
ShortJump);
masm.as_dbar(0);
masm.bind(&done);
}
} // namespace
void MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic) {
if (framePushed() % ABIStackAlignment != 0) {
aic.alignmentPadding = ABIStackAlignment - (framePushed() % ABIStackAlignment);
@ -3244,6 +3378,246 @@ void MacroAssemblerLOONGARCH64Compat::storePtr(Register src, AbsoluteAddress des
storePtr(src, Address(scratch, 0));
}
void MacroAssemblerLOONGARCH64Compat::atomicEffectOp(
int nbytes, AtomicOp op, Imm32 value, const Address& address,
Register valueTemp, Register offsetTemp, Register maskTemp) {
AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp,
offsetTemp, maskTemp, InvalidReg);
}
void MacroAssemblerLOONGARCH64Compat::atomicEffectOp(
int nbytes, AtomicOp op, Imm32 value, const BaseIndex& address,
Register valueTemp, Register offsetTemp, Register maskTemp) {
AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp,
offsetTemp, maskTemp, InvalidReg);
}
void MacroAssemblerLOONGARCH64Compat::atomicEffectOp(
int nbytes, AtomicOp op, Register value, const Address& address,
Register valueTemp, Register offsetTemp, Register maskTemp) {
AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp,
offsetTemp, maskTemp, InvalidReg);
}
void MacroAssemblerLOONGARCH64Compat::atomicEffectOp(
int nbytes, AtomicOp op, Register value, const BaseIndex& address,
Register valueTemp, Register offsetTemp, Register maskTemp) {
AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp,
offsetTemp, maskTemp, InvalidReg);
}
void MacroAssemblerLOONGARCH64Compat::atomicFetchOp(
int nbytes, bool signExtend, AtomicOp op, Imm32 value,
const Address& address, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address,
valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::atomicFetchOp(
int nbytes, bool signExtend, AtomicOp op, Imm32 value,
const BaseIndex& address, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address,
valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::atomicFetchOp(
int nbytes, bool signExtend, AtomicOp op, Register value,
const Address& address, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address,
valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::atomicFetchOp(
int nbytes, bool signExtend, AtomicOp op, Register value,
const BaseIndex& address, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address,
valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::compareExchange(
int nbytes, bool signExtend, const Address& address, Register oldval,
Register newval, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
CompareExchangeLoongArch64(*this, nbytes, signExtend, address, oldval,
newval, valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::compareExchange(
int nbytes, bool signExtend, const BaseIndex& address, Register oldval,
Register newval, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output) {
CompareExchangeLoongArch64(*this, nbytes, signExtend, address, oldval,
newval, valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::compareExchangeToTypedIntArray(
Scalar::Type arrayType, const Address& mem, Register oldval,
Register newval, Register temp, Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output) {
switch (arrayType) {
case Scalar::Int8:
compareExchange(1, true, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint8:
compareExchange(1, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int16:
compareExchange(2, true, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint16:
compareExchange(2, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int32:
compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint32:
MOZ_ASSERT(output.isFloat());
MOZ_ASSERT(temp != InvalidReg);
compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
void MacroAssemblerLOONGARCH64Compat::compareExchangeToTypedIntArray(
Scalar::Type arrayType, const BaseIndex& mem, Register oldval,
Register newval, Register temp, Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output) {
switch (arrayType) {
case Scalar::Int8:
compareExchange(1, true, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint8:
compareExchange(1, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int16:
compareExchange(2, true, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint16:
compareExchange(2, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Int32:
compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, output.gpr());
break;
case Scalar::Uint32:
MOZ_ASSERT(output.isFloat());
MOZ_ASSERT(temp != InvalidReg);
compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp,
maskTemp, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
void MacroAssemblerLOONGARCH64Compat::atomicExchange(
int nbytes, bool signExtend, const Address& address, Register value,
Register valueTemp, Register offsetTemp, Register maskTemp,
Register output) {
CompareExchangeLoongArch64(*this, nbytes, signExtend, address, InvalidReg,
value, valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::atomicExchange(
int nbytes, bool signExtend, const BaseIndex& address, Register value,
Register valueTemp, Register offsetTemp, Register maskTemp,
Register output) {
CompareExchangeLoongArch64(*this, nbytes, signExtend, address, InvalidReg,
value, valueTemp, offsetTemp, maskTemp, output);
}
void MacroAssemblerLOONGARCH64Compat::atomicExchangeToTypedIntArray(
Scalar::Type arrayType, const Address& mem, Register value, Register temp,
Register valueTemp, Register offsetTemp, Register maskTemp,
AnyRegister output) {
switch (arrayType) {
case Scalar::Int8:
atomicExchange(1, true, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint8:
atomicExchange(1, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Int16:
atomicExchange(2, true, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint16:
atomicExchange(2, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Int32:
atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint32:
MOZ_ASSERT(output.isFloat());
MOZ_ASSERT(temp != InvalidReg);
atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp,
temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
void MacroAssemblerLOONGARCH64Compat::atomicExchangeToTypedIntArray(
Scalar::Type arrayType, const BaseIndex& mem, Register value,
Register temp, Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output) {
switch (arrayType) {
case Scalar::Int8:
atomicExchange(1, true, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint8:
atomicExchange(1, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Int16:
atomicExchange(2, true, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint16:
atomicExchange(2, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Int32:
atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp,
output.gpr());
break;
case Scalar::Uint32:
MOZ_ASSERT(output.isFloat());
MOZ_ASSERT(temp != InvalidReg);
atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp,
temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
void MacroAssemblerLOONGARCH64Compat::testNullSet(Condition cond,
const ValueOperand& value,
Register dest) {

View file

@ -1272,6 +1272,66 @@ class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 {
void storePtr(Register src, const BaseIndex& address);
void storePtr(Register src, AbsoluteAddress dest);
void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value,
const Address& address, Register valueTemp,
Register offsetTemp, Register maskTemp);
void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value,
const BaseIndex& address, Register valueTemp,
Register offsetTemp, Register maskTemp);
void atomicEffectOp(int nbytes, AtomicOp op, Register value,
const Address& address, Register valueTemp,
Register offsetTemp, Register maskTemp);
void atomicEffectOp(int nbytes, AtomicOp op, Register value,
const BaseIndex& address, Register valueTemp,
Register offsetTemp, Register maskTemp);
void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value,
const Address& address, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value,
const BaseIndex& address, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value,
const Address& address, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value,
const BaseIndex& address, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void compareExchange(int nbytes, bool signExtend, const Address& address,
Register oldval, Register newval, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void compareExchange(int nbytes, bool signExtend, const BaseIndex& address,
Register oldval, Register newval, Register valueTemp,
Register offsetTemp, Register maskTemp, Register output);
void compareExchangeToTypedIntArray(Scalar::Type arrayType,
const Address& mem, Register oldval,
Register newval, Register temp,
Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output);
void compareExchangeToTypedIntArray(Scalar::Type arrayType,
const BaseIndex& mem, Register oldval,
Register newval, Register temp,
Register valueTemp, Register offsetTemp,
Register maskTemp, AnyRegister output);
void atomicExchange(int nbytes, bool signExtend, const Address& address,
Register value, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output);
void atomicExchange(int nbytes, bool signExtend, const BaseIndex& address,
Register value, Register valueTemp, Register offsetTemp,
Register maskTemp, Register output);
void atomicExchangeToTypedIntArray(Scalar::Type arrayType,
const Address& mem, Register value,
Register temp, Register valueTemp,
Register offsetTemp, Register maskTemp,
AnyRegister output);
void atomicExchangeToTypedIntArray(Scalar::Type arrayType,
const BaseIndex& mem, Register value,
Register temp, Register valueTemp,
Register offsetTemp, Register maskTemp,
AnyRegister output);
void moveDouble(FloatRegister src, FloatRegister dest) {
as_fmov_d(dest, src);
}