mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 08:07:30 +09:00
Issue #3049 - Enable loongarch64 JIT atomics
This commit is contained in:
parent
bb16a45039
commit
4c58aa2724
3 changed files with 699 additions and 16 deletions
|
|
@ -306,58 +306,307 @@ CodeGeneratorLoongArch64::visitWasmAddOffset(LWasmAddOffset* lir)
|
||||||
masm.branchPtr(Assembler::Below, out, limitBase, trap(mir, wasm::Trap::OutOfBounds));
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
|
CodeGeneratorLoongArch64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
|
||||||
{
|
{
|
||||||
(void)ins;
|
MAsmJSCompareExchangeHeap* mir = ins->mir();
|
||||||
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins)
|
CodeGeneratorLoongArch64::visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins)
|
||||||
{
|
{
|
||||||
(void)ins;
|
MAsmJSAtomicExchangeHeap* mir = ins->mir();
|
||||||
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
|
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
|
||||||
{
|
{
|
||||||
(void)ins;
|
MOZ_ASSERT(ins->mir()->hasUses());
|
||||||
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins)
|
CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins)
|
||||||
{
|
{
|
||||||
(void)ins;
|
MOZ_ASSERT(!ins->mir()->hasUses());
|
||||||
MOZ_CRASH("asm.js atomics are not supported on loongarch64 yet");
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir)
|
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir)
|
||||||
{
|
{
|
||||||
(void)lir;
|
MOZ_ASSERT(lir->mir()->hasUses());
|
||||||
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
|
|
||||||
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir)
|
CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir)
|
||||||
{
|
{
|
||||||
(void)lir;
|
MOZ_ASSERT(!lir->mir()->hasUses());
|
||||||
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
|
|
||||||
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
|
CodeGeneratorLoongArch64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
|
||||||
{
|
{
|
||||||
(void)lir;
|
Register elements = ToRegister(lir->elements());
|
||||||
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
|
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
|
void
|
||||||
CodeGeneratorLoongArch64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
|
CodeGeneratorLoongArch64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
|
||||||
{
|
{
|
||||||
(void)lir;
|
Register elements = ToRegister(lir->elements());
|
||||||
MOZ_CRASH("atomics are not supported on loongarch64 Ion yet");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,140 @@
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace jit {
|
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) {
|
void MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic) {
|
||||||
if (framePushed() % ABIStackAlignment != 0) {
|
if (framePushed() % ABIStackAlignment != 0) {
|
||||||
aic.alignmentPadding = ABIStackAlignment - (framePushed() % ABIStackAlignment);
|
aic.alignmentPadding = ABIStackAlignment - (framePushed() % ABIStackAlignment);
|
||||||
|
|
@ -3244,6 +3378,246 @@ void MacroAssemblerLOONGARCH64Compat::storePtr(Register src, AbsoluteAddress des
|
||||||
storePtr(src, Address(scratch, 0));
|
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,
|
void MacroAssemblerLOONGARCH64Compat::testNullSet(Condition cond,
|
||||||
const ValueOperand& value,
|
const ValueOperand& value,
|
||||||
Register dest) {
|
Register dest) {
|
||||||
|
|
|
||||||
|
|
@ -1272,6 +1272,66 @@ class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 {
|
||||||
void storePtr(Register src, const BaseIndex& address);
|
void storePtr(Register src, const BaseIndex& address);
|
||||||
void storePtr(Register src, AbsoluteAddress dest);
|
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) {
|
void moveDouble(FloatRegister src, FloatRegister dest) {
|
||||||
as_fmov_d(dest, src);
|
as_fmov_d(dest, src);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue