diff --git a/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp b/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp index f93cca6d65..47be6e5725 100644 --- a/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp +++ b/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp @@ -306,58 +306,307 @@ CodeGeneratorLoongArch64::visitWasmAddOffset(LWasmAddOffset* lir) masm.branchPtr(Assembler::Below, out, limitBase, trap(mir, wasm::Trap::OutOfBounds)); } +template +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 +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 +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 +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); + } } diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp index 994f11faa5..0536008882 100644 --- a/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp @@ -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 +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 +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 +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) { diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.h b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h index 0c70e3968a..af2a29de76 100644 --- a/js/src/jit/loongarch64/MacroAssembler-loongarch64.h +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h @@ -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); }