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:
Ivica Bogosavljevic 2018-11-13 15:31:10 +01:00 committed by Commit Bot
parent bfb5728266
commit 01f7ff5493
10 changed files with 294 additions and 113 deletions

View File

@ -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: {

View File

@ -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);
}

View File

@ -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,

View File

@ -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)

View File

@ -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) {

View File

@ -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-----------

View File

@ -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:

View File

@ -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:

View File

@ -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'

View File

@ -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();
}