Bug 1638295 - [MIPS] Support inlining Atomics functions for BigInt64/BigUint64.r=lth

Inline Atomics.load, Atomics.store, Atomics.compareExchange,
Atomics.exchange and Atomics.{add,and,or,sub,xor}.

Differential Revision: https://phabricator.services.mozilla.com/D107366
This commit is contained in:
Liu Yu 2021-03-29 08:23:31 +00:00
parent 51709b916b
commit cae2b31f7a
8 changed files with 309 additions and 62 deletions

View File

@ -3666,11 +3666,13 @@ class MacroAssembler : public MacroAssemblerSpecific {
void compareExchange64(const Synchronization& sync, const Address& mem,
Register64 expected, Register64 replacement,
Register64 output) DEFINED_ON(arm, arm64, x64, x86);
Register64 output)
DEFINED_ON(arm, arm64, x64, x86, mips64);
void compareExchange64(const Synchronization& sync, const BaseIndex& mem,
Register64 expected, Register64 replacement,
Register64 output) DEFINED_ON(arm, arm64, x64, x86);
Register64 output)
DEFINED_ON(arm, arm64, x64, x86, mips64);
// Exchange with memory. Return the value initially in memory.
// MIPS: `valueTemp`, `offsetTemp` and `maskTemp` must be defined for 8-bit
@ -3700,11 +3702,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
void atomicExchange64(const Synchronization& sync, const Address& mem,
Register64 value, Register64 output)
DEFINED_ON(arm, arm64, x64, x86);
DEFINED_ON(arm, arm64, x64, x86, mips64);
void atomicExchange64(const Synchronization& sync, const BaseIndex& mem,
Register64 value, Register64 output)
DEFINED_ON(arm, arm64, x64, x86);
DEFINED_ON(arm, arm64, x64, x86, mips64);
// Read-modify-write with memory. Return the value in memory before the
// operation.
@ -3759,7 +3761,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const Address& mem, Register64 temp,
Register64 output) DEFINED_ON(arm, arm64, x64);
Register64 output) DEFINED_ON(arm, arm64, x64, mips64);
void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
const Address& value, const Address& mem,
@ -3767,7 +3769,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const BaseIndex& mem, Register64 temp,
Register64 output) DEFINED_ON(arm, arm64, x64);
Register64 output) DEFINED_ON(arm, arm64, x64, mips64);
void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
const Address& value, const BaseIndex& mem,
@ -3785,14 +3787,14 @@ class MacroAssembler : public MacroAssemblerSpecific {
void atomicEffectOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const Address& mem, Register64 temp)
DEFINED_ON(arm, arm64);
DEFINED_ON(arm, arm64, mips64);
void atomicEffectOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const BaseIndex& mem) DEFINED_ON(x64);
void atomicEffectOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const BaseIndex& mem, Register64 temp)
DEFINED_ON(arm, arm64);
DEFINED_ON(arm, arm64, mips64);
// 64-bit atomic load. On 64-bit systems, use regular load with
// Synchronization::Load, not this method.

View File

@ -2168,30 +2168,113 @@ void CodeGenerator::visitAtomicExchangeTypedArrayElement(
}
}
void CodeGenerator::visitAtomicLoad64(LAtomicLoad64* lir) { MOZ_CRASH("NYI"); }
void CodeGenerator::visitAtomicStore64(LAtomicStore64* lir) {
MOZ_CRASH("NYI");
}
void CodeGenerator::visitCompareExchangeTypedArrayElement64(
LCompareExchangeTypedArrayElement64* lir) {
MOZ_CRASH("NYI");
Register elements = ToRegister(lir->elements());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Register64 temp1 = ToRegister64(lir->temp1());
Register64 temp2 = ToRegister64(lir->temp2());
Register out = ToRegister(lir->output());
Register64 tempOut(out);
Scalar::Type arrayType = lir->mir()->arrayType();
masm.loadBigInt64(oldval, temp1);
masm.loadBigInt64(newval, tempOut);
if (lir->index()->isConstant()) {
Address dest = ToAddress(elements, lir->index(), arrayType);
masm.compareExchange64(Synchronization::Full(), dest, temp1, tempOut,
temp2);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromScalarType(arrayType));
masm.compareExchange64(Synchronization::Full(), dest, temp1, tempOut,
temp2);
}
emitCreateBigInt(lir, arrayType, temp2, out, temp1.scratchReg());
}
void CodeGenerator::visitAtomicExchangeTypedArrayElement64(
LAtomicExchangeTypedArrayElement64* lir) {
MOZ_CRASH("NYI");
Register elements = ToRegister(lir->elements());
Register value = ToRegister(lir->value());
Register64 temp1 = ToRegister64(lir->temp1());
Register64 temp2 = Register64(ToRegister(lir->temp2()));
Register out = ToRegister(lir->output());
Scalar::Type arrayType = lir->mir()->arrayType();
masm.loadBigInt64(value, temp1);
if (lir->index()->isConstant()) {
Address dest = ToAddress(elements, lir->index(), arrayType);
masm.atomicExchange64(Synchronization::Full(), dest, temp1, temp2);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromScalarType(arrayType));
masm.atomicExchange64(Synchronization::Full(), dest, temp1, temp2);
}
emitCreateBigInt(lir, arrayType, temp2, out, temp1.scratchReg());
}
void CodeGenerator::visitAtomicTypedArrayElementBinop64(
LAtomicTypedArrayElementBinop64* lir) {
MOZ_CRASH("NYI");
MOZ_ASSERT(lir->mir()->hasUses());
Register elements = ToRegister(lir->elements());
Register value = ToRegister(lir->value());
Register64 temp1 = ToRegister64(lir->temp1());
Register64 temp2 = ToRegister64(lir->temp2());
Register out = ToRegister(lir->output());
Register64 tempOut = Register64(out);
Scalar::Type arrayType = lir->mir()->arrayType();
AtomicOp atomicOp = lir->mir()->operation();
masm.loadBigInt64(value, temp1);
if (lir->index()->isConstant()) {
Address dest = ToAddress(elements, lir->index(), arrayType);
masm.atomicFetchOp64(Synchronization::Full(), atomicOp, temp1, dest,
tempOut, temp2);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromScalarType(arrayType));
masm.atomicFetchOp64(Synchronization::Full(), atomicOp, temp1, dest,
tempOut, temp2);
}
emitCreateBigInt(lir, arrayType, temp2, out, temp1.scratchReg());
}
void CodeGenerator::visitAtomicTypedArrayElementBinopForEffect64(
LAtomicTypedArrayElementBinopForEffect64* lir) {
MOZ_CRASH("NYI");
MOZ_ASSERT(!lir->mir()->hasUses());
Register elements = ToRegister(lir->elements());
Register value = ToRegister(lir->value());
Register64 temp1 = ToRegister64(lir->temp1());
Register64 temp2 = ToRegister64(lir->temp2());
Scalar::Type arrayType = lir->mir()->arrayType();
AtomicOp atomicOp = lir->mir()->operation();
masm.loadBigInt64(value, temp1);
if (lir->index()->isConstant()) {
Address dest = ToAddress(elements, lir->index(), arrayType);
masm.atomicEffectOp64(Synchronization::Full(), atomicOp, temp1, dest,
temp2);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromScalarType(arrayType));
masm.atomicEffectOp64(Synchronization::Full(), atomicOp, temp1, dest,
temp2);
}
}
void CodeGenerator::visitWasmCompareExchangeI64(LWasmCompareExchangeI64* lir) {

View File

@ -602,16 +602,23 @@ void LIRGenerator::visitCompareExchangeTypedArrayElement(
const LAllocation index =
useRegisterOrIndexConstant(ins->index(), ins->arrayType());
const LAllocation newval = useRegister(ins->newval());
const LAllocation oldval = useRegister(ins->oldval());
if (Scalar::isBigIntType(ins->arrayType())) {
MOZ_CRASH("NYI");
LInt64Definition temp1 = tempInt64();
LInt64Definition temp2 = tempInt64();
auto* lir = new (alloc()) LCompareExchangeTypedArrayElement64(
elements, index, oldval, newval, temp1, temp2);
define(lir, ins);
assignSafepoint(lir, ins);
return;
}
// If the target is a floating register then we need a temp at the
// CodeGenerator level for creating the result.
const LAllocation newval = useRegister(ins->newval());
const LAllocation oldval = useRegister(ins->oldval());
LDefinition outTemp = LDefinition::BogusTemp();
LDefinition valueTemp = LDefinition::BogusTemp();
LDefinition offsetTemp = LDefinition::BogusTemp();
@ -637,8 +644,6 @@ void LIRGenerator::visitCompareExchangeTypedArrayElement(
void LIRGenerator::visitAtomicExchangeTypedArrayElement(
MAtomicExchangeTypedArrayElement* ins) {
MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32);
MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
@ -646,14 +651,24 @@ void LIRGenerator::visitAtomicExchangeTypedArrayElement(
const LAllocation index =
useRegisterOrIndexConstant(ins->index(), ins->arrayType());
const LAllocation value = useRegister(ins->value());
if (Scalar::isBigIntType(ins->arrayType())) {
MOZ_CRASH("NYI");
LInt64Definition temp1 = tempInt64();
LDefinition temp2 = temp();
auto* lir = new (alloc()) LAtomicExchangeTypedArrayElement64(
elements, index, value, temp1, temp2);
define(lir, ins);
assignSafepoint(lir, ins);
return;
}
// If the target is a floating register then we need a temp at the
// CodeGenerator level for creating the result.
const LAllocation value = useRegister(ins->value());
MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32);
LDefinition outTemp = LDefinition::BogusTemp();
LDefinition valueTemp = LDefinition::BogusTemp();
LDefinition offsetTemp = LDefinition::BogusTemp();
@ -677,14 +692,6 @@ void LIRGenerator::visitAtomicExchangeTypedArrayElement(
define(lir, ins);
}
void LIRGeneratorMIPSShared::lowerAtomicLoad64(MLoadUnboxedScalar* ins) {
MOZ_CRASH("NYI");
}
void LIRGeneratorMIPSShared::lowerAtomicStore64(MStoreUnboxedScalar* ins) {
MOZ_CRASH("NYI");
}
void LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) {
MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
@ -794,7 +801,27 @@ void LIRGenerator::visitAtomicTypedArrayElementBinop(
const LAllocation value = useRegister(ins->value());
if (Scalar::isBigIntType(ins->arrayType())) {
MOZ_CRASH("NYI");
LInt64Definition temp1 = tempInt64();
LInt64Definition temp2 = tempInt64();
// Case 1: the result of the operation is not used.
//
// We can omit allocating the result BigInt.
if (ins->isForEffect()) {
auto* lir = new (alloc()) LAtomicTypedArrayElementBinopForEffect64(
elements, index, value, temp1, temp2);
add(lir, ins);
return;
}
// Case 2: the result of the operation is used.
auto* lir = new (alloc())
LAtomicTypedArrayElementBinop64(elements, index, value, temp1, temp2);
define(lir, ins);
assignSafepoint(lir, ins);
return;
}
LDefinition valueTemp = LDefinition::BogusTemp();

View File

@ -69,9 +69,6 @@ class LIRGeneratorMIPSShared : public LIRGeneratorShared {
void lowerBigIntLsh(MBigIntLsh* ins);
void lowerBigIntRsh(MBigIntRsh* ins);
void lowerAtomicLoad64(MLoadUnboxedScalar* ins);
void lowerAtomicStore64(MStoreUnboxedScalar* ins);
LTableSwitch* newLTableSwitch(const LAllocation& in,
const LDefinition& inputCopy,
MTableSwitch* ins);

View File

@ -514,3 +514,48 @@ void CodeGenerator::visitTestI64AndBranch(LTestI64AndBranch* lir) {
emitBranch(input.reg, Imm32(0), Assembler::NonZero, ifTrue, ifFalse);
}
void CodeGenerator::visitAtomicLoad64(LAtomicLoad64* lir) {
Register elements = ToRegister(lir->elements());
Register temp = ToRegister(lir->temp());
Register64 temp64 = ToRegister64(lir->temp64());
Register out = ToRegister(lir->output());
const MLoadUnboxedScalar* mir = lir->mir();
Scalar::Type storageType = mir->storageType();
auto sync = Synchronization::Load();
masm.memoryBarrierBefore(sync);
if (lir->index()->isConstant()) {
Address source =
ToAddress(elements, lir->index(), storageType, mir->offsetAdjustment());
masm.load64(source, temp64);
} else {
BaseIndex source(elements, ToRegister(lir->index()),
ScaleFromScalarType(storageType), mir->offsetAdjustment());
masm.load64(source, temp64);
}
masm.memoryBarrierAfter(sync);
emitCreateBigInt(lir, storageType, temp64, out, temp);
}
void CodeGenerator::visitAtomicStore64(LAtomicStore64* lir) {
Register elements = ToRegister(lir->elements());
Register value = ToRegister(lir->value());
Register64 temp1 = ToRegister64(lir->temp1());
Scalar::Type writeType = lir->mir()->writeType();
masm.loadBigInt64(value, temp1);
auto sync = Synchronization::Store();
masm.memoryBarrierBefore(sync);
if (lir->index()->isConstant()) {
Address dest = ToAddress(elements, lir->index(), writeType);
masm.store64(temp1, dest);
} else {
BaseIndex dest(elements, ToRegister(lir->index()),
ScaleFromScalarType(writeType));
masm.store64(temp1, dest);
}
masm.memoryBarrierAfter(sync);
}

View File

@ -88,6 +88,25 @@ void LIRGeneratorMIPS64::lowerBigIntMod(MBigIntMod* ins) {
assignSafepoint(lir, ins);
}
void LIRGeneratorMIPS64::lowerAtomicLoad64(MLoadUnboxedScalar* ins) {
const LUse elements = useRegister(ins->elements());
const LAllocation index =
useRegisterOrIndexConstant(ins->index(), ins->storageType());
auto* lir = new (alloc()) LAtomicLoad64(elements, index, temp(), tempInt64());
define(lir, ins);
assignSafepoint(lir, ins);
}
void LIRGeneratorMIPS64::lowerAtomicStore64(MStoreUnboxedScalar* ins) {
LUse elements = useRegister(ins->elements());
LAllocation index =
useRegisterOrIndexConstant(ins->index(), ins->writeType());
LAllocation value = useRegister(ins->value());
add(new (alloc()) LAtomicStore64(elements, index, value, tempInt64()), ins);
}
void LIRGenerator::visitBox(MBox* box) {
MDefinition* opd = box->getOperand(0);

View File

@ -43,6 +43,9 @@ class LIRGeneratorMIPS64 : public LIRGeneratorMIPSShared {
void lowerBigIntDiv(MBigIntDiv* ins);
void lowerBigIntMod(MBigIntMod* ins);
void lowerAtomicLoad64(MLoadUnboxedScalar* ins);
void lowerAtomicStore64(MStoreUnboxedScalar* ins);
};
typedef LIRGeneratorMIPS64 LIRGeneratorSpecific;

View File

@ -2561,20 +2561,24 @@ void MacroAssemblerMIPS64Compat::wasmStoreI64Impl(
}
template <typename T>
static void WasmCompareExchange64(MacroAssembler& masm,
const wasm::MemoryAccessDesc& access,
const T& mem, Register64 expect,
Register64 replace, Register64 output) {
static void CompareExchange64(MacroAssembler& masm,
const wasm::MemoryAccessDesc* access,
const Synchronization& sync, const T& mem,
Register64 expect, Register64 replace,
Register64 output) {
MOZ_ASSERT(oldval != output && newval != output);
masm.computeEffectiveAddress(mem, SecondScratchReg);
Label tryAgain;
Label exit;
masm.memoryBarrierBefore(access.sync());
masm.memoryBarrierBefore(sync);
masm.bind(&tryAgain);
masm.append(access, masm.size());
if (access) {
masm.append(*access, masm.size());
}
masm.as_lld(output.reg, SecondScratchReg, 0);
masm.ma_b(output.reg, expect.reg, &exit, Assembler::NotEqual, ShortJump);
@ -2583,7 +2587,7 @@ static void WasmCompareExchange64(MacroAssembler& masm,
masm.ma_b(ScratchRegister, ScratchRegister, &tryAgain, Assembler::Zero,
ShortJump);
masm.memoryBarrierAfter(access.sync());
masm.memoryBarrierAfter(sync);
masm.bind(&exit);
}
@ -2593,7 +2597,8 @@ void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
Register64 expect,
Register64 replace,
Register64 output) {
WasmCompareExchange64(*this, access, mem, expect, replace, output);
CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
output);
}
void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
@ -2601,58 +2606,100 @@ void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
Register64 expect,
Register64 replace,
Register64 output) {
WasmCompareExchange64(*this, access, mem, expect, replace, output);
CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
output);
}
void MacroAssembler::compareExchange64(const Synchronization& sync,
const Address& mem, Register64 expect,
Register64 replace, Register64 output) {
CompareExchange64(*this, nullptr, sync, mem, expect, replace, output);
}
void MacroAssembler::compareExchange64(const Synchronization& sync,
const BaseIndex& mem, Register64 expect,
Register64 replace, Register64 output) {
CompareExchange64(*this, nullptr, sync, mem, expect, replace, output);
}
template <typename T>
static void AtomicExchange64(MacroAssembler& masm,
const wasm::MemoryAccessDesc& access, const T& mem,
Register64 src, Register64 output) {
const wasm::MemoryAccessDesc* access,
const Synchronization& sync, const T& mem,
Register64 value, Register64 output) {
MOZ_ASSERT(value != output);
masm.computeEffectiveAddress(mem, SecondScratchReg);
Label tryAgain;
masm.memoryBarrierBefore(access.sync());
masm.memoryBarrierBefore(sync);
masm.bind(&tryAgain);
masm.append(access, masm.size());
masm.as_lld(output.reg, SecondScratchReg, 0);
if (access) {
masm.append(*access, masm.size());
}
masm.movePtr(src.reg, ScratchRegister);
masm.as_lld(output.reg, SecondScratchReg, 0);
masm.movePtr(value.reg, ScratchRegister);
masm.as_scd(ScratchRegister, SecondScratchReg, 0);
masm.ma_b(ScratchRegister, ScratchRegister, &tryAgain, Assembler::Zero,
ShortJump);
masm.memoryBarrierAfter(access.sync());
masm.memoryBarrierAfter(sync);
}
template <typename T>
static void WasmAtomicExchange64(MacroAssembler& masm,
const wasm::MemoryAccessDesc& access,
const T& mem, Register64 value,
Register64 output) {
AtomicExchange64(masm, &access, access.sync(), mem, value, output);
}
void MacroAssembler::wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
const Address& mem, Register64 src,
Register64 output) {
AtomicExchange64(*this, access, mem, src, output);
WasmAtomicExchange64(*this, access, mem, src, output);
}
void MacroAssembler::wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
const BaseIndex& mem, Register64 src,
Register64 output) {
AtomicExchange64(*this, access, mem, src, output);
WasmAtomicExchange64(*this, access, mem, src, output);
}
void MacroAssembler::atomicExchange64(const Synchronization& sync,
const Address& mem, Register64 value,
Register64 output) {
AtomicExchange64(*this, nullptr, sync, mem, value, output);
}
void MacroAssembler::atomicExchange64(const Synchronization& sync,
const BaseIndex& mem, Register64 value,
Register64 output) {
AtomicExchange64(*this, nullptr, sync, mem, value, output);
}
template <typename T>
static void AtomicFetchOp64(MacroAssembler& masm,
const wasm::MemoryAccessDesc& access, AtomicOp op,
const wasm::MemoryAccessDesc* access,
const Synchronization& sync, AtomicOp op,
Register64 value, const T& mem, Register64 temp,
Register64 output) {
MOZ_ASSERT(value != output);
MOZ_ASSERT(value != temp);
masm.computeEffectiveAddress(mem, SecondScratchReg);
Label tryAgain;
masm.memoryBarrierBefore(access.sync());
masm.memoryBarrierBefore(sync);
masm.bind(&tryAgain);
if (access) {
masm.append(*access, masm.size());
}
masm.append(access, masm.size());
masm.as_lld(output.reg, SecondScratchReg, 0);
switch (op) {
@ -2678,21 +2725,45 @@ static void AtomicFetchOp64(MacroAssembler& masm,
masm.as_scd(temp.reg, SecondScratchReg, 0);
masm.ma_b(temp.reg, temp.reg, &tryAgain, Assembler::Zero, ShortJump);
masm.memoryBarrierAfter(access.sync());
masm.memoryBarrierAfter(sync);
}
void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
AtomicOp op, Register64 value,
const Address& mem, Register64 temp,
Register64 output) {
AtomicFetchOp64(*this, access, op, value, mem, temp, output);
AtomicFetchOp64(*this, &access, access.sync(), op, value, mem, temp, output);
}
void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
AtomicOp op, Register64 value,
const BaseIndex& mem, Register64 temp,
Register64 output) {
AtomicFetchOp64(*this, access, op, value, mem, temp, output);
AtomicFetchOp64(*this, &access, access.sync(), op, value, mem, temp, output);
}
void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const Address& mem,
Register64 temp, Register64 output) {
AtomicFetchOp64(*this, nullptr, sync, op, value, mem, temp, output);
}
void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const BaseIndex& mem,
Register64 temp, Register64 output) {
AtomicFetchOp64(*this, nullptr, sync, op, value, mem, temp, output);
}
void MacroAssembler::atomicEffectOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const Address& mem,
Register64 temp) {
AtomicFetchOp64(*this, nullptr, sync, op, value, mem, temp, temp);
}
void MacroAssembler::atomicEffectOp64(const Synchronization& sync, AtomicOp op,
Register64 value, const BaseIndex& mem,
Register64 temp) {
AtomicFetchOp64(*this, nullptr, sync, op, value, mem, temp, temp);
}
// ========================================================================