MIPS32: Implement AtomicPair operators through runtime
This CL implements AtomicPair operators: Load, Store, Add, Sub, Or, Xor, And, Exchange and CompareExchange using runtime on MIPS32R2 and older. MIPS32R6 includes instructions for 64-bit atomic access so they are implemented using those. Change-Id: I1309c1ea4771480516ec5a92f7592533bdcb205c Reviewed-on: https://chromium-review.googlesource.com/c/1326466 Reviewed-by: Sreten Kovacevic <skovacevic@wavecomp.com> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Ivica Bogosavljevic <ibogosavljevic@wavecomp.com> Cr-Commit-Position: refs/heads/master@{#57496}
This commit is contained in:
parent
bfb5728266
commit
01f7ff5493
@ -339,39 +339,63 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC64_LOGIC_BINOP(bin_instr) \
|
||||
#define ASSEMBLE_ATOMIC64_LOGIC_BINOP(bin_instr, external) \
|
||||
do { \
|
||||
if (IsMipsArchVariant(kMips32r6)) { \
|
||||
Label binop; \
|
||||
Register oldval_low = \
|
||||
instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1); \
|
||||
Register oldval_high = \
|
||||
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2); \
|
||||
__ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ llwp(i.TempRegister(0), i.TempRegister(1), i.InputRegister(2)); \
|
||||
__ bin_instr(i.TempRegister(0), i.TempRegister(1), i.TempRegister(0), \
|
||||
i.TempRegister(1), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ scwp(i.TempRegister(0), i.TempRegister(1), i.InputRegister(2)); \
|
||||
__ llx(oldval_high, MemOperand(i.TempRegister(0), 4)); \
|
||||
__ ll(oldval_low, MemOperand(i.TempRegister(0), 0)); \
|
||||
__ bin_instr(i.TempRegister(1), i.TempRegister(2), oldval_low, \
|
||||
oldval_high, i.InputRegister(2), i.InputRegister(3)); \
|
||||
__ scx(i.TempRegister(2), MemOperand(i.TempRegister(0), 4)); \
|
||||
__ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} else { \
|
||||
UNREACHABLE(); \
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL); \
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1); \
|
||||
__ PrepareCallCFunction(3, 0, kScratchReg); \
|
||||
__ CallCFunction(ExternalReference::external(), 3, 0); \
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC64_ARITH_BINOP(bin_instr) \
|
||||
do { \
|
||||
if (IsMipsArchVariant(kMips32r6)) { \
|
||||
Label binop; \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ llwp(i.TempRegister(0), i.TempRegister(1), i.InputRegister(2)); \
|
||||
__ bin_instr(i.TempRegister(0), i.TempRegister(1), i.TempRegister(0), \
|
||||
i.TempRegister(1), i.InputRegister(0), i.InputRegister(1), \
|
||||
i.TempRegister(2), i.TempRegister(3)); \
|
||||
__ scwp(i.TempRegister(0), i.TempRegister(1), i.InputRegister(2)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} else { \
|
||||
UNREACHABLE(); \
|
||||
} \
|
||||
#define ASSEMBLE_ATOMIC64_ARITH_BINOP(bin_instr, external) \
|
||||
do { \
|
||||
if (IsMipsArchVariant(kMips32r6)) { \
|
||||
Label binop; \
|
||||
Register oldval_low = \
|
||||
instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1); \
|
||||
Register oldval_high = \
|
||||
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2); \
|
||||
__ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ llx(oldval_high, MemOperand(i.TempRegister(0), 4)); \
|
||||
__ ll(oldval_low, MemOperand(i.TempRegister(0), 0)); \
|
||||
__ bin_instr(i.TempRegister(1), i.TempRegister(2), oldval_low, \
|
||||
oldval_high, i.InputRegister(2), i.InputRegister(3), \
|
||||
kScratchReg, kScratchReg2); \
|
||||
__ scx(i.TempRegister(2), MemOperand(i.TempRegister(0), 4)); \
|
||||
__ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} else { \
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL); \
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1); \
|
||||
__ PrepareCallCFunction(3, 0, kScratchReg); \
|
||||
__ CallCFunction(ExternalReference::external(), 3, 0); \
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr) \
|
||||
@ -1725,57 +1749,120 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
#undef ATOMIC_BINOP_CASE
|
||||
case kMipsWord32AtomicPairLoad: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Register second_output =
|
||||
instr->OutputCount() == 2 ? i.OutputRegister(1) : i.TempRegister(0);
|
||||
__ llwp(i.OutputRegister(0), second_output, i.InputRegister(0));
|
||||
__ sync();
|
||||
if (instr->OutputCount() > 0) {
|
||||
Register second_output = instr->OutputCount() == 2
|
||||
? i.OutputRegister(1)
|
||||
: i.TempRegister(1);
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ llx(second_output, MemOperand(a0, 4));
|
||||
__ ll(i.OutputRegister(0), MemOperand(a0, 0));
|
||||
__ sync();
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL);
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
__ PrepareCallCFunction(1, 0, kScratchReg);
|
||||
__ CallCFunction(ExternalReference::atomic_pair_load_function(), 1, 0);
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kMipsWord32AtomicPairStore: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Label store;
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ sync();
|
||||
__ bind(&store);
|
||||
__ llwp(i.TempRegister(0), i.TempRegister(1), i.InputRegister(0));
|
||||
__ Move(i.TempRegister(0), i.InputRegister(2));
|
||||
__ scwp(i.InputRegister(1), i.TempRegister(0), i.InputRegister(0));
|
||||
__ BranchShort(&store, eq, i.TempRegister(0), Operand(zero_reg));
|
||||
__ llx(i.TempRegister(2), MemOperand(a0, 4));
|
||||
__ ll(i.TempRegister(1), MemOperand(a0, 0));
|
||||
__ Move(i.TempRegister(1), i.InputRegister(2));
|
||||
__ scx(i.InputRegister(3), MemOperand(a0, 4));
|
||||
__ sc(i.TempRegister(1), MemOperand(a0, 0));
|
||||
__ BranchShort(&store, eq, i.TempRegister(1), Operand(zero_reg));
|
||||
__ sync();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL);
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ PushCallerSaved(kDontSaveFPRegs);
|
||||
__ PrepareCallCFunction(3, 0, kScratchReg);
|
||||
__ CallCFunction(ExternalReference::atomic_pair_store_function(), 3, 0);
|
||||
__ PopCallerSaved(kDontSaveFPRegs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#define ATOMIC64_BINOP_ARITH_CASE(op, instr) \
|
||||
case kMipsWord32AtomicPair##op: \
|
||||
ASSEMBLE_ATOMIC64_ARITH_BINOP(instr); \
|
||||
#define ATOMIC64_BINOP_ARITH_CASE(op, instr, external) \
|
||||
case kMipsWord32AtomicPair##op: \
|
||||
ASSEMBLE_ATOMIC64_ARITH_BINOP(instr, external); \
|
||||
break;
|
||||
ATOMIC64_BINOP_ARITH_CASE(Add, AddPair)
|
||||
ATOMIC64_BINOP_ARITH_CASE(Sub, SubPair)
|
||||
ATOMIC64_BINOP_ARITH_CASE(Add, AddPair, atomic_pair_add_function)
|
||||
ATOMIC64_BINOP_ARITH_CASE(Sub, SubPair, atomic_pair_sub_function)
|
||||
#undef ATOMIC64_BINOP_ARITH_CASE
|
||||
#define ATOMIC64_BINOP_LOGIC_CASE(op, instr) \
|
||||
case kMipsWord32AtomicPair##op: \
|
||||
ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr); \
|
||||
#define ATOMIC64_BINOP_LOGIC_CASE(op, instr, external) \
|
||||
case kMipsWord32AtomicPair##op: \
|
||||
ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr, external); \
|
||||
break;
|
||||
ATOMIC64_BINOP_LOGIC_CASE(And, AndPair)
|
||||
ATOMIC64_BINOP_LOGIC_CASE(Or, OrPair)
|
||||
ATOMIC64_BINOP_LOGIC_CASE(Xor, XorPair)
|
||||
ATOMIC64_BINOP_LOGIC_CASE(And, AndPair, atomic_pair_and_function)
|
||||
ATOMIC64_BINOP_LOGIC_CASE(Or, OrPair, atomic_pair_or_function)
|
||||
ATOMIC64_BINOP_LOGIC_CASE(Xor, XorPair, atomic_pair_xor_function)
|
||||
#undef ATOMIC64_BINOP_LOGIC_CASE
|
||||
case kMipsWord32AtomicPairExchange:
|
||||
UNREACHABLE();
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Label binop;
|
||||
Register oldval_low =
|
||||
instr->OutputCount() >= 1 ? i.OutputRegister(0) : i.TempRegister(1);
|
||||
Register oldval_high =
|
||||
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(2);
|
||||
__ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
|
||||
__ sync();
|
||||
__ bind(&binop);
|
||||
__ llx(oldval_high, MemOperand(i.TempRegister(0), 4));
|
||||
__ ll(oldval_low, MemOperand(i.TempRegister(0), 0));
|
||||
__ Move(i.TempRegister(1), i.InputRegister(2));
|
||||
__ scx(i.InputRegister(3), MemOperand(i.TempRegister(0), 4));
|
||||
__ sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));
|
||||
__ sync();
|
||||
} else {
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL);
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
__ PrepareCallCFunction(3, 0, kScratchReg);
|
||||
__ Addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ CallCFunction(ExternalReference::atomic_pair_exchange_function(), 3,
|
||||
0);
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
}
|
||||
break;
|
||||
case kMipsWord32AtomicPairCompareExchange: {
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL);
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
__ PrepareCallCFunction(5, 0, kScratchReg);
|
||||
__ addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ sw(i.InputRegister(5), MemOperand(sp, 16));
|
||||
__ CallCFunction(
|
||||
ExternalReference::atomic_pair_compare_exchange_function(), 5, 0);
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Label compareExchange, exit;
|
||||
Register oldval_low =
|
||||
instr->OutputCount() >= 1 ? i.OutputRegister(0) : kScratchReg;
|
||||
Register oldval_high =
|
||||
instr->OutputCount() >= 2 ? i.OutputRegister(1) : kScratchReg2;
|
||||
__ Addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
|
||||
__ sync();
|
||||
__ bind(&compareExchange);
|
||||
__ llx(oldval_high, MemOperand(i.TempRegister(0), 4));
|
||||
__ ll(oldval_low, MemOperand(i.TempRegister(0), 0));
|
||||
__ BranchShort(&exit, ne, i.InputRegister(2), Operand(oldval_low));
|
||||
__ BranchShort(&exit, ne, i.InputRegister(3), Operand(oldval_high));
|
||||
__ mov(kScratchReg, i.InputRegister(4));
|
||||
__ scx(i.InputRegister(5), MemOperand(i.TempRegister(0), 4));
|
||||
__ sc(kScratchReg, MemOperand(i.TempRegister(0), 0));
|
||||
__ BranchShort(&compareExchange, eq, kScratchReg, Operand(zero_reg));
|
||||
__ bind(&exit);
|
||||
__ sync();
|
||||
} else {
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL);
|
||||
__ PushCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
__ PrepareCallCFunction(5, 0, kScratchReg);
|
||||
__ addu(a0, i.InputRegister(0), i.InputRegister(1));
|
||||
__ sw(i.InputRegister(5), MemOperand(sp, 16));
|
||||
__ CallCFunction(
|
||||
ExternalReference::atomic_pair_compare_exchange_function(), 5, 0);
|
||||
__ PopCallerSaved(kDontSaveFPRegs, v0, v1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kMipsS128Zero: {
|
||||
|
@ -235,29 +235,29 @@ static void VisitPairAtomicBinop(InstructionSelector* selector, Node* node,
|
||||
Node* value = node->InputAt(2);
|
||||
Node* value_high = node->InputAt(3);
|
||||
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
|
||||
selector->Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
|
||||
InstructionOperand inputs[] = {g.UseRegister(value),
|
||||
g.UseRegister(value_high), addr_reg};
|
||||
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
|
||||
g.TempRegister(), g.TempRegister()};
|
||||
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
|
||||
g.UseFixed(value, a1),
|
||||
g.UseFixed(value_high, a2)};
|
||||
Node* projection0 = NodeProperties::FindProjection(node, 0);
|
||||
Node* projection1 = NodeProperties::FindProjection(node, 1);
|
||||
if (projection1) {
|
||||
InstructionOperand outputs[] = {g.DefineAsRegister(projection0),
|
||||
g.DefineAsRegister(projection1)};
|
||||
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, v0),
|
||||
g.DefineAsFixed(projection1, v1)};
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(),
|
||||
g.TempRegister()};
|
||||
selector->Emit(opcode | AddressingModeField::encode(kMode_None),
|
||||
arraysize(outputs), outputs, arraysize(inputs), inputs,
|
||||
arraysize(temps), temps);
|
||||
} else if (projection0) {
|
||||
InstructionOperand outputs[] = {g.DefineAsRegister(projection0)};
|
||||
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, v0)};
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(v1),
|
||||
g.TempRegister()};
|
||||
selector->Emit(opcode | AddressingModeField::encode(kMode_None),
|
||||
arraysize(outputs), outputs, arraysize(inputs), inputs,
|
||||
arraysize(temps), temps);
|
||||
} else {
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(v0),
|
||||
g.TempRegister(v1)};
|
||||
selector->Emit(opcode | AddressingModeField::encode(kMode_None), 0, nullptr,
|
||||
arraysize(inputs), inputs, arraysize(temps), temps);
|
||||
}
|
||||
@ -688,24 +688,24 @@ void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
|
||||
Node* projection0 = NodeProperties::FindProjection(node, 0);
|
||||
Node* projection1 = NodeProperties::FindProjection(node, 1);
|
||||
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
InstructionOperand inputs[] = {addr_reg};
|
||||
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index)};
|
||||
|
||||
InstructionOperand temps[] = {g.TempRegister()};
|
||||
if (projection1) {
|
||||
InstructionOperand outputs[] = {g.DefineAsRegister(projection0),
|
||||
g.DefineAsRegister(projection1)};
|
||||
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, v0),
|
||||
g.DefineAsFixed(projection1, v1)};
|
||||
InstructionOperand temps[] = {g.TempRegister(a0)};
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), arraysize(outputs),
|
||||
outputs, arraysize(inputs), inputs, 1, temps);
|
||||
outputs, arraysize(inputs), inputs, arraysize(temps), temps);
|
||||
} else if (projection0) {
|
||||
InstructionOperand outputs[] = {g.DefineAsRegister(projection0)};
|
||||
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, v0)};
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(v1)};
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), arraysize(outputs),
|
||||
outputs, arraysize(inputs), inputs, 1, temps);
|
||||
outputs, arraysize(inputs), inputs, arraysize(temps), temps);
|
||||
} else {
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(v0),
|
||||
g.TempRegister(v1)};
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), 0, nullptr,
|
||||
arraysize(inputs), inputs, 1, temps);
|
||||
arraysize(inputs), inputs, arraysize(temps), temps);
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,13 +716,11 @@ void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
|
||||
Node* value_low = node->InputAt(2);
|
||||
Node* value_high = node->InputAt(3);
|
||||
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
|
||||
InstructionOperand inputs[] = {addr_reg, g.UseRegister(value_low),
|
||||
g.UseRegister(value_high)};
|
||||
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
|
||||
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
|
||||
g.UseFixed(value_low, a1),
|
||||
g.UseFixed(value_high, a2)};
|
||||
InstructionOperand temps[] = {g.TempRegister(a0), g.TempRegister(),
|
||||
g.TempRegister()};
|
||||
Emit(kMipsWord32AtomicPairStore | AddressingModeField::encode(kMode_MRI), 0,
|
||||
nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
|
||||
}
|
||||
|
@ -991,6 +991,95 @@ ExternalReference ExternalReference::fixed_typed_array_base_data_offset() {
|
||||
FixedTypedArrayBase::kDataOffset - kHeapObjectTag));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_load(intptr_t address) {
|
||||
return std::atomic_load(reinterpret_cast<std::atomic<int64_t>*>(address));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_load_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_load)));
|
||||
}
|
||||
|
||||
static void atomic_pair_store(intptr_t address, int value_low, int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
std::atomic_store(reinterpret_cast<std::atomic<int64_t>*>(address), value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_store_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_store)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_add(intptr_t address, int value_low,
|
||||
int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_fetch_add(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_add_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_add)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_sub(intptr_t address, int value_low,
|
||||
int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_fetch_sub(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_sub_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_sub)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_and(intptr_t address, int value_low,
|
||||
int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_fetch_and(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_and_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_and)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_or(intptr_t address, int value_low, int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_fetch_or(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_or_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_or)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_xor(intptr_t address, int value_low,
|
||||
int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_fetch_xor(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_xor_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_xor)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_exchange(intptr_t address, int value_low,
|
||||
int value_high) {
|
||||
int64_t value =
|
||||
static_cast<int64_t>(value_high) << 32 | (value_low & 0xFFFFFFFF);
|
||||
return std::atomic_exchange(reinterpret_cast<std::atomic<int64_t>*>(address),
|
||||
value);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::atomic_pair_exchange_function() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(atomic_pair_exchange)));
|
||||
}
|
||||
|
||||
static uint64_t atomic_pair_compare_exchange(intptr_t address,
|
||||
int old_value_low,
|
||||
int old_value_high,
|
||||
|
@ -177,6 +177,14 @@ class StatsCounter;
|
||||
V(wasm_word32_ror, "wasm::word32_ror") \
|
||||
V(wasm_word64_ctz, "wasm::word64_ctz") \
|
||||
V(wasm_word64_popcnt, "wasm::word64_popcnt") \
|
||||
V(atomic_pair_load_function, "atomic_pair_load_function") \
|
||||
V(atomic_pair_store_function, "atomic_pair_store_function") \
|
||||
V(atomic_pair_add_function, "atomic_pair_add_function") \
|
||||
V(atomic_pair_sub_function, "atomic_pair_sub_function") \
|
||||
V(atomic_pair_and_function, "atomic_pair_and_function") \
|
||||
V(atomic_pair_or_function, "atomic_pair_or_function") \
|
||||
V(atomic_pair_xor_function, "atomic_pair_xor_function") \
|
||||
V(atomic_pair_exchange_function, "atomic_pair_exchange_function") \
|
||||
V(atomic_pair_compare_exchange_function, \
|
||||
"atomic_pair_compare_exchange_function") \
|
||||
EXTERNAL_REFERENCE_LIST_INTL(V)
|
||||
|
@ -2358,14 +2358,16 @@ void Assembler::sc(Register rd, const MemOperand& rs) {
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::llwp(Register rd, Register rt, Register base) {
|
||||
void Assembler::llx(Register rd, const MemOperand& rs) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
GenInstrRegister(SPECIAL3, base, rt, rd, 1, LL_R6);
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 1, LL_R6);
|
||||
}
|
||||
|
||||
void Assembler::scwp(Register rd, Register rt, Register base) {
|
||||
void Assembler::scx(Register rd, const MemOperand& rs) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
GenInstrRegister(SPECIAL3, base, rt, rd, 1, SC_R6);
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 1, SC_R6);
|
||||
}
|
||||
|
||||
void Assembler::lui(Register rd, int32_t j) {
|
||||
|
@ -890,8 +890,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
|
||||
void ll(Register rd, const MemOperand& rs);
|
||||
void sc(Register rd, const MemOperand& rs);
|
||||
void llwp(Register rd, Register rt, Register base);
|
||||
void scwp(Register rd, Register rt, Register base);
|
||||
void llx(Register rd, const MemOperand& rs);
|
||||
void scx(Register rd, const MemOperand& rs);
|
||||
|
||||
// ---------PC-Relative-instructions-----------
|
||||
|
||||
|
@ -1686,7 +1686,11 @@ void Decoder::DecodeTypeImmediateSPECIAL3(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case LL_R6: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Format(instr, "ll 'rt, 'imm9s('rs)");
|
||||
if (instr->Bit(6)) {
|
||||
Format(instr, "llx 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Format(instr, "ll 'rt, 'imm9s('rs)");
|
||||
}
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
@ -1694,7 +1698,11 @@ void Decoder::DecodeTypeImmediateSPECIAL3(Instruction* instr) {
|
||||
}
|
||||
case SC_R6: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Format(instr, "sc 'rt, 'imm9s('rs)");
|
||||
if (instr->Bit(6)) {
|
||||
Format(instr, "scx 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Format(instr, "sc 'rt, 'imm9s('rs)");
|
||||
}
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
@ -1962,14 +1970,14 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "ll 'rt, 'imm16s('rs)");
|
||||
Format(instr, "ll 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case SC:
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "sc 'rt, 'imm16s('rs)");
|
||||
Format(instr, "sc 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case LWC1:
|
||||
|
@ -4240,21 +4240,6 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
|
||||
SetResult(rd_reg(), alu_out);
|
||||
break;
|
||||
}
|
||||
case LL_R6: {
|
||||
// LLWP/SCWP sequence cannot be simulated properly
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
set_register(rd_reg(), ReadW(rs() + 4, instr_.instr()));
|
||||
set_register(rt(), ReadW(rs(), instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SC_R6: {
|
||||
// LLWP/SCWP sequence cannot be simulated properly
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
WriteW(rs() + 4, rd_reg(), instr_.instr());
|
||||
WriteW(rs(), rt(), instr_.instr());
|
||||
set_register(rt(), 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -6833,8 +6818,12 @@ void Simulator::DecodeTypeImmediate() {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
int32_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
int32_t bit6 = instr_.Bit(6);
|
||||
WriteW(base + offset9, rt, instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
// Only SC (and not SCX) instruction modifies rt_reg
|
||||
if (bit6 == 0) {
|
||||
set_register(rt_reg, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -356,7 +356,7 @@
|
||||
}], # '(arch == mipsel or arch == mips64el or arch == mips or arch == mips64) and not simd_mips'
|
||||
|
||||
##############################################################################
|
||||
['arch == mipsel or arch == mips64el or arch == mips or arch == mips64', {
|
||||
['arch == mips or arch == mips64', {
|
||||
# TODO(mips-team): Implement I64Atomic operations on MIPS
|
||||
'test-run-wasm-atomics64/*': [SKIP],
|
||||
}], # 'arch == mipsel or arch == mips64el or arch == mips or arch == mips64'
|
||||
|
@ -1123,11 +1123,11 @@ TEST(madd_msub_maddf_msubf) {
|
||||
TEST(atomic_load_store) {
|
||||
SET_UP();
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "7c62ffb6 ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "7c6200a6 sc v0, 1(v1)");
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "7c62ffb6 ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "7c6200a6 sc v0, 1(v1)");
|
||||
} else {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "c062ffff ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "e0620001 sc v0, 1(v1)");
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "c062ffff ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "e0620001 sc v0, 1(v1)");
|
||||
}
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user