Commit 11245b26 authored by Deepti Gandluri's avatar Deepti Gandluri Committed by Commit Bot

[compiler] Fix use of projection nodes for I64Atomic ops

Handle the case when one or both of the output nodes of an I64Atomic op
are optimized, for code-gen instructions that use a set of fixed
registers, use temp registers to ensure the registers are not
clobbered.

BUG:v8:6532


Change-Id: I52763c48d615cdf3ae8d754402b11da2df31a4a1
Reviewed-on: https://chromium-review.googlesource.com/1195910Reviewed-by: 's avatarBill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Commit-Queue: Deepti Gandluri <gdeepti@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56004}
parent 15d6d7b4
......@@ -422,11 +422,9 @@ void ComputePoisonedAddressForLoad(CodeGenerator* codegen,
__ add(i.TempRegister(0), i.InputRegister(2), i.InputRegister(3)); \
__ dmb(ISH); \
__ bind(&binop); \
__ ldrexd(i.OutputRegister(0), i.OutputRegister(1), i.TempRegister(0)); \
__ instr1(i.TempRegister(1), i.OutputRegister(0), i.InputRegister(0), \
SBit::SetCC); \
__ instr2(i.TempRegister(2), i.OutputRegister(1), \
Operand(i.InputRegister(1))); \
__ ldrexd(r2, r3, i.TempRegister(0)); \
__ instr1(i.TempRegister(1), r2, i.InputRegister(0), SBit::SetCC); \
__ instr2(i.TempRegister(2), r3, Operand(i.InputRegister(1))); \
DCHECK_EQ(LeaveCC, i.OutputSBit()); \
__ strexd(i.TempRegister(3), i.TempRegister(1), i.TempRegister(2), \
i.TempRegister(0)); \
......@@ -435,17 +433,15 @@ void ComputePoisonedAddressForLoad(CodeGenerator* codegen,
__ dmb(ISH); \
} while (0)
#define ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr) \
#define ASSEMBLE_ATOMIC64_LOGIC_BINOP(foo) \
do { \
Label binop; \
__ add(i.TempRegister(0), i.InputRegister(2), i.InputRegister(3)); \
__ dmb(ISH); \
__ bind(&binop); \
__ ldrexd(i.OutputRegister(0), i.OutputRegister(1), i.TempRegister(0)); \
__ instr(i.TempRegister(1), i.OutputRegister(0), \
Operand(i.InputRegister(0))); \
__ instr(i.TempRegister(2), i.OutputRegister(1), \
Operand(i.InputRegister(1))); \
__ ldrexd(r2, r3, i.TempRegister(0)); \
__ foo(i.TempRegister(1), r2, Operand(i.InputRegister(0))); \
__ foo(i.TempRegister(2), r3, Operand(i.InputRegister(1))); \
__ strexd(i.TempRegister(3), i.TempRegister(1), i.TempRegister(2), \
i.TempRegister(0)); \
__ teq(i.TempRegister(3), Operand(0)); \
......@@ -602,6 +598,19 @@ void AdjustStackPointerForTailCall(
}
}
#if DEBUG
bool VerifyOutputOfAtomicPairInstr(ArmOperandConverter* converter,
const Instruction* instr, Register low,
Register high) {
if (instr->OutputCount() > 0) {
if (converter->OutputRegister(0) != low) return false;
if (instr->OutputCount() == 2 && converter->OutputRegister(1) != high)
return false;
}
return true;
}
#endif
} // namespace
void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
......@@ -2746,11 +2755,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ATOMIC_BINOP_CASE(Or, orr)
ATOMIC_BINOP_CASE(Xor, eor)
#undef ATOMIC_BINOP_CASE
case kArmWord32AtomicPairLoad:
case kArmWord32AtomicPairLoad: {
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr, r0, r1));
__ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
__ ldrexd(i.OutputRegister(0), i.OutputRegister(1), i.TempRegister(0));
__ ldrexd(r0, r1, i.TempRegister(0));
__ dmb(ISH);
break;
}
case kArmWord32AtomicPairStore: {
Label store;
__ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
......@@ -2766,26 +2777,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
#define ATOMIC_ARITH_BINOP_CASE(op, instr1, instr2) \
case kArmWord32AtomicPair##op: { \
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr, r2, r3)); \
ASSEMBLE_ATOMIC64_ARITH_BINOP(instr1, instr2); \
break; \
}
ATOMIC_ARITH_BINOP_CASE(Add, add, adc)
ATOMIC_ARITH_BINOP_CASE(Sub, sub, sbc)
#undef ATOMIC_ARITH_BINOP_CASE
#define ATOMIC_LOGIC_BINOP_CASE(op, instr) \
#define ATOMIC_LOGIC_BINOP_CASE(op, instr1) \
case kArmWord32AtomicPair##op: { \
ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr); \
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr, r2, r3)); \
ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr1); \
break; \
}
ATOMIC_LOGIC_BINOP_CASE(And, and_)
ATOMIC_LOGIC_BINOP_CASE(Or, orr)
ATOMIC_LOGIC_BINOP_CASE(Xor, eor)
#undef ATOMIC_LOGIC_BINOP_CASE
case kArmWord32AtomicPairExchange: {
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr, r6, r7));
Label exchange;
__ add(i.TempRegister(0), i.InputRegister(2), i.InputRegister(3));
__ dmb(ISH);
__ bind(&exchange);
__ ldrexd(i.OutputRegister(0), i.OutputRegister(1), i.TempRegister(0));
__ ldrexd(r6, r7, i.TempRegister(0));
__ strexd(i.TempRegister(1), i.InputRegister(0), i.InputRegister(1),
i.TempRegister(0));
__ teq(i.TempRegister(1), Operand(0));
......@@ -2794,15 +2809,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmWord32AtomicPairCompareExchange: {
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr, r2, r3));
__ add(i.TempRegister(0), i.InputRegister(4), i.InputRegister(5));
Label compareExchange;
Label exit;
__ dmb(ISH);
__ bind(&compareExchange);
__ ldrexd(i.OutputRegister(0), i.OutputRegister(1), i.TempRegister(0));
__ teq(i.InputRegister(0), Operand(i.OutputRegister(0)));
__ ldrexd(r2, r3, i.TempRegister(0));
__ teq(i.InputRegister(0), Operand(r2));
__ b(ne, &exit);
__ teq(i.InputRegister(1), Operand(i.OutputRegister(1)));
__ teq(i.InputRegister(1), Operand(r3));
__ b(ne, &exit);
__ strexd(i.TempRegister(1), i.InputRegister(2), i.InputRegister(3),
i.TempRegister(0));
......@@ -2812,7 +2828,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ dmb(ISH);
break;
}
#undef ATOMIC_LOGIC_BINOP_CASE
#undef ASSEMBLE_ATOMIC_LOAD_INTEGER
#undef ASSEMBLE_ATOMIC_STORE_INTEGER
#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
......
......@@ -414,14 +414,30 @@ void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
InstructionOperand inputs[] = {g.UseUniqueRegister(value),
g.UseUniqueRegister(value_high),
g.UseRegister(base), g.UseRegister(index)};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r2),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), r3)};
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2),
g.DefineAsFixed(projection1, r3)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
g.TempRegister(r7), g.TempRegister()};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
g.TempRegister(r7), g.TempRegister(),
g.TempRegister(r3)};
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
g.TempRegister(r7), g.TempRegister(),
g.TempRegister(r2), g.TempRegister(r3)};
selector->Emit(code, 0, nullptr, arraysize(inputs), inputs,
arraysize(temps), temps);
}
}
} // namespace
......@@ -2246,16 +2262,28 @@ void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
ArmOperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index)};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r0),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), r1)};
InstructionOperand temps[] = {g.TempRegister()};
AddressingMode addressing_mode = kMode_Offset_RR;
InstructionCode code =
kArmWord32AtomicPairLoad | AddressingModeField::encode(addressing_mode);
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index)};
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r0),
g.DefineAsFixed(projection1, r1)};
InstructionOperand temps[] = {g.TempRegister()};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r0)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r1)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r0),
g.TempRegister(r1)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
}
}
void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
......@@ -2305,14 +2333,27 @@ void InstructionSelector::VisitWord32AtomicPairExchange(Node* node) {
InstructionOperand inputs[] = {g.UseFixed(value, r0),
g.UseFixed(value_high, r1),
g.UseRegister(base), g.UseRegister(index)};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r6),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), r7)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
InstructionCode code = kArmWord32AtomicPairExchange |
AddressingModeField::encode(addressing_mode);
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r6),
g.DefineAsFixed(projection1, r7)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r6)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister(r7)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister(r6), g.TempRegister(r7)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
}
}
void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
......@@ -2322,14 +2363,28 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
g.UseFixed(node->InputAt(2), r4), g.UseFixed(node->InputAt(3), r5),
g.UseFixed(node->InputAt(4), r8), g.UseFixed(node->InputAt(5), r9),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r2),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), r3)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
InstructionCode code = kArmWord32AtomicPairCompareExchange |
AddressingModeField::encode(addressing_mode);
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2),
g.DefineAsFixed(projection1, r3)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else if (projection0) {
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r2)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister(r3)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister(r2), g.TempRegister(r3)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
}
}
#define SIMD_TYPE_LIST(V) \
......
......@@ -431,12 +431,12 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
do { \
Label binop; \
__ bind(&binop); \
__ mov(i.OutputRegister(0), i.MemoryOperand(2)); \
__ mov(i.OutputRegister(1), i.NextMemoryOperand(2)); \
__ mov(eax, i.MemoryOperand(2)); \
__ mov(edx, i.NextMemoryOperand(2)); \
__ push(i.InputRegister(0)); \
__ push(i.InputRegister(1)); \
__ instr1(i.InputRegister(0), i.OutputRegister(0)); \
__ instr2(i.InputRegister(1), i.OutputRegister(1)); \
__ instr1(i.InputRegister(0), eax); \
__ instr2(i.InputRegister(1), edx); \
__ lock(); \
__ cmpxchg8b(i.MemoryOperand(2)); \
__ pop(i.InputRegister(1)); \
......@@ -547,6 +547,18 @@ void AdjustStackPointerForTailCall(TurboAssembler* tasm,
}
}
#ifdef DEBUG
bool VerifyOutputOfAtomicPairInstr(IA32OperandConverter* converter,
const Instruction* instr) {
if (instr->OutputCount() > 0) {
if (converter->OutputRegister(0) != eax) return false;
if (instr->OutputCount() == 2 && converter->OutputRegister(1) != edx)
return false;
}
return true;
}
#endif
} // namespace
void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
......@@ -3639,8 +3651,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIA32Word32AtomicPairLoad: {
XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
__ movq(tmp, i.MemoryOperand());
if (instr->OutputCount() == 2) {
__ Pextrd(i.OutputRegister(0), tmp, 0);
__ Pextrd(i.OutputRegister(1), tmp, 1);
} else if (instr->OutputCount() == 1) {
__ Pextrd(i.OutputRegister(0), tmp, 0);
__ Pextrd(i.TempRegister(1), tmp, 1);
}
break;
}
case kIA32Word32AtomicPairStore: {
......@@ -3675,8 +3692,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kIA32Word32AtomicPairExchange: {
__ mov(i.OutputRegister(0), i.MemoryOperand(2));
__ mov(i.OutputRegister(1), i.NextMemoryOperand(2));
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr));
__ mov(eax, i.MemoryOperand(2));
__ mov(edx, i.NextMemoryOperand(2));
__ lock();
__ cmpxchg8b(i.MemoryOperand(2));
break;
......@@ -3748,6 +3766,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
#undef ATOMIC_BINOP_CASE
#define ATOMIC_BINOP_CASE(op, instr1, instr2) \
case kIA32Word32AtomicPair##op: { \
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr)); \
ASSEMBLE_I64ATOMIC_BINOP(instr1, instr2) \
break; \
}
......@@ -3757,11 +3776,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ATOMIC_BINOP_CASE(Xor, xor_, xor_)
#undef ATOMIC_BINOP_CASE
case kIA32Word32AtomicPairSub: {
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr));
Label binop;
__ bind(&binop);
// Move memory operand into edx:eax
__ mov(i.OutputRegister(0), i.MemoryOperand(2));
__ mov(i.OutputRegister(1), i.NextMemoryOperand(2));
__ mov(eax, i.MemoryOperand(2));
__ mov(edx, i.NextMemoryOperand(2));
// Save input registers temporarily on the stack.
__ push(i.InputRegister(0));
__ push(i.InputRegister(1));
......@@ -3770,8 +3790,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ adc(i.InputRegister(1), 0);
__ neg(i.InputRegister(1));
// Add memory operand, negated input.
__ add(i.InputRegister(0), i.OutputRegister(0));
__ adc(i.InputRegister(1), i.OutputRegister(1));
__ add(i.InputRegister(0), eax);
__ adc(i.InputRegister(1), edx);
__ lock();
__ cmpxchg8b(i.MemoryOperand(2));
// Restore input registers
......
......@@ -1351,11 +1351,24 @@ void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
g.UseFixed(value, ebx), g.UseFixed(value_high, ecx),
g.UseUniqueRegister(base),
g.GetEffectiveIndexOperand(index, &addressing_mode)};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax),
g.DefineAsFixed(projection1, edx)};
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs),
inputs);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax)};
InstructionOperand temps[] = {g.TempRegister(edx)};
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
selector->Emit(code, 0, nullptr, arraysize(inputs), inputs,
arraysize(temps), temps);
}
}
} // namespace
......@@ -1745,14 +1758,27 @@ void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
Node* index = node->InputAt(1);
InstructionOperand inputs[] = {g.UseUniqueRegister(base),
g.GetEffectiveIndexOperand(index, &mode)};
InstructionOperand temps[] = {g.TempDoubleRegister()};
InstructionOperand outputs[] = {
g.DefineAsRegister(NodeProperties::FindProjection(node, 0)),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionCode code =
kIA32Word32AtomicPairLoad | AddressingModeField::encode(mode);
if (projection1) {
InstructionOperand temps[] = {g.TempDoubleRegister()};
InstructionOperand outputs[] = {g.DefineAsRegister(projection0),
g.DefineAsRegister(projection1)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else if (projection0) {
InstructionOperand temps[] = {g.TempDoubleRegister(), g.TempRegister()};
InstructionOperand outputs[] = {g.DefineAsRegister(projection0)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempDoubleRegister(), g.TempRegister(),
g.TempRegister()};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
}
}
void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
......@@ -1812,12 +1838,23 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
// InputAt(0) => base
g.UseUniqueRegister(node->InputAt(0)),
g.GetEffectiveIndexOperand(index, &addressing_mode)};
InstructionOperand outputs[] = {
g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionCode code = kIA32Word32AtomicPairCompareExchange |
AddressingModeField::encode(addressing_mode);
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax),
g.DefineAsFixed(projection1, edx)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax)};
InstructionOperand temps[] = {g.TempRegister(edx)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
}
}
#define SIMD_INT_TYPES(V) \
......
......@@ -354,6 +354,172 @@ WASM_EXEC_TEST(I64AtomicStoreLoad8U) {
}
}
// Drop tests verify atomic operations are run correctly when the
// entire 64-bit output is optimized out
void RunDropTest(ExecutionTier execution_tier, WasmOpcode wasm_op,
Uint64BinOp op) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint64_t, uint64_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
r.builder().SetHasSharedMemory();
BUILD(r,
WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0),
MachineRepresentation::kWord64),
WASM_DROP, WASM_GET_LOCAL(0));
uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(local, r.Call(local));
uint64_t expected = op(initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
#define TEST_OPERATION(Name) \
WASM_EXEC_TEST(I64Atomic##Name##Drop) { \
RunDropTest(execution_tier, kExprI64Atomic##Name, Name); \
}
OPERATION_LIST(TEST_OPERATION)
#undef TEST_OPERATION
WASM_EXEC_TEST(I64AtomicSub16UDrop) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint64_t, uint64_t> r(execution_tier);
uint16_t* memory =
r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
r.builder().SetHasSharedMemory();
BUILD(r,
WASM_ATOMICS_BINOP(kExprI64AtomicSub16U, WASM_I32V_1(0),
WASM_GET_LOCAL(0), MachineRepresentation::kWord16),
WASM_DROP, WASM_GET_LOCAL(0));
uint16_t initial = 0x7, local = 0xffe0;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(local, r.Call(local));
uint16_t expected = Sub(initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
WASM_EXEC_TEST(I64AtomicCompareExchangeDrop) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
r.builder().SetHasSharedMemory();
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
BUILD(r,
WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange, WASM_I32V_1(0),
WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
MachineRepresentation::kWord64),
WASM_DROP, WASM_GET_LOCAL(1));
uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(local, r.Call(initial, local));
uint64_t expected = CompareExchange(initial, initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
WASM_EXEC_TEST(I64AtomicStoreLoadDrop) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
r.builder().SetHasSharedMemory();
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
BUILD(r,
WASM_ATOMICS_STORE_OP(kExprI64AtomicStore, WASM_ZERO, WASM_GET_LOCAL(0),
MachineRepresentation::kWord64),
WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad, WASM_ZERO,
MachineRepresentation::kWord64),
WASM_DROP, WASM_GET_LOCAL(1));
uint64_t store_value = 0x1111111111111111, expected = 0xC0DE;
CHECK_EQ(expected, r.Call(store_value, expected));
CHECK_EQ(store_value, r.builder().ReadMemory(&memory[0]));
}
WASM_EXEC_TEST(I64AtomicAddConvertDrop) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint64_t, uint64_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
r.builder().SetHasSharedMemory();
BUILD(r,
WASM_ATOMICS_BINOP(kExprI64AtomicAdd, WASM_I32V_1(0), WASM_GET_LOCAL(0),
MachineRepresentation::kWord64),
kExprI32ConvertI64, WASM_DROP, WASM_GET_LOCAL(0));
uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(local, r.Call(local));
uint64_t expected = Add(initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
WASM_EXEC_TEST(I64AtomicLoadConvertDrop) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint64_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
r.builder().SetHasSharedMemory();
BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_LOAD_OP(
kExprI64AtomicLoad, WASM_ZERO, MachineRepresentation::kWord64)));
uint64_t initial = 0x1111222233334444;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(static_cast<uint32_t>(initial), r.Call(initial));
}
// Convert tests verify atomic operations are run correctly when the
// upper half of the 64-bit output is optimized out
void RunConvertTest(ExecutionTier execution_tier, WasmOpcode wasm_op,
Uint64BinOp op) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint64_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
r.builder().SetHasSharedMemory();
BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_BINOP(
kExprI64AtomicAdd, WASM_ZERO, WASM_GET_LOCAL(0),
MachineRepresentation::kWord64)));
uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(static_cast<uint32_t>(initial), r.Call(local));
uint64_t expected = Add(initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
#define TEST_OPERATION(Name) \
WASM_EXEC_TEST(I64AtomicConvert##Name) { \
RunConvertTest(execution_tier, kExprI64Atomic##Name, Name); \
}
OPERATION_LIST(TEST_OPERATION)
#undef TEST_OPERATION
WASM_EXEC_TEST(I64AtomicConvertCompareExchange) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint64_t, uint64_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
r.builder().SetHasSharedMemory();
BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
kExprI64AtomicCompareExchange, WASM_I32V_1(0), WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1), MachineRepresentation::kWord64)));
uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
r.builder().WriteMemory(&memory[0], initial);
CHECK_EQ(static_cast<uint32_t>(initial), r.Call(initial, local));
uint64_t expected = CompareExchange(initial, initial, local);
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
}
} // namespace test_run_wasm_atomics_64
} // namespace wasm
} // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment