[turbofan] Don't assume that Word32AtomicPairCompareExchange has a projection-0

The instruction selector assumed for Word32AtomicPairCompareExchange
nodes that if there exists a Projection(1) user, then there also exists
a Projection(0) user. This, however, is not the case, because TurboFan
eliminates unreachable nodes. The missing projection node lead to a
failed DCHECK in the register allocator.

With this CL we allocate the right registers for the existing
projections, and allocate the other needed registers as temp registers.

R=gdeepti@chromium.org

Bug: v8:10140
Change-Id: Id50768c3cb712db5e0eb3b9dcd0a8a479e20953a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2030731
Reviewed-by: Deepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66122}
This commit is contained in:
Andreas Haas 2020-01-30 16:02:15 +01:00 committed by Commit Bot
parent 148b53910e
commit bc436ed752
3 changed files with 59 additions and 29 deletions

View File

@ -2458,24 +2458,24 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
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);
InstructionOperand outputs[2];
size_t output_count = 0;
InstructionOperand temps[4];
size_t temp_count = 0;
temps[temp_count++] = g.TempRegister();
temps[temp_count++] = g.TempRegister();
if (projection0) {
outputs[output_count++] = g.DefineAsFixed(projection0, r2);
} else {
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister(r2), g.TempRegister(r3)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
temps[temp_count++] = g.TempRegister(r2);
}
if (projection1) {
outputs[output_count++] = g.DefineAsFixed(projection1, r3);
} else {
temps[temp_count++] = g.TempRegister(r3);
}
Emit(code, output_count, outputs, arraysize(inputs), inputs, temp_count,
temps);
}
#define SIMD_TYPE_LIST(V) \

View File

@ -1999,21 +1999,22 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
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, 0, {});
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax)};
InstructionOperand temps[] = {g.TempRegister(edx)};
const int num_temps = arraysize(temps);
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
num_temps, temps);
InstructionOperand outputs[2];
size_t output_count = 0;
InstructionOperand temps[2];
size_t temp_count = 0;
if (projection0) {
outputs[output_count++] = g.DefineAsFixed(projection0, eax);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
const int num_temps = arraysize(temps);
Emit(code, 0, nullptr, arraysize(inputs), inputs, num_temps, temps);
temps[temp_count++] = g.TempRegister(eax);
}
if (projection1) {
outputs[output_count++] = g.DefineAsFixed(projection1, edx);
} else {
temps[temp_count++] = g.TempRegister(edx);
}
Emit(code, output_count, outputs, arraysize(inputs), inputs, temp_count,
temps);
}
#define SIMD_INT_TYPES(V) \

View File

@ -752,6 +752,35 @@ WASM_EXEC_TEST(I64AtomicAddUseOnlyHighWord) {
CHECK_EQ(0x12345678, r.Call());
}
WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyLowWord) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
memory[1] = 0x1234567890abcdeful;
r.builder().SetHasSharedMemory();
// Test that we can use just the low word of an I64AtomicLoad.
BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
kExprI64AtomicCompareExchange, WASM_I32V(8), WASM_I64V(1),
WASM_I64V(memory[1]), MachineRepresentation::kWord64)));
CHECK_EQ(0x90abcdef, r.Call());
}
WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyHighWord) {
EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t> r(execution_tier);
uint64_t* memory =
r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
memory[1] = 0x1234567890abcdeful;
r.builder().SetHasSharedMemory();
// Test that we can use just the high word of an I64AtomicLoad.
BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_ROR(
WASM_ATOMICS_TERNARY_OP(
kExprI64AtomicCompareExchange, WASM_I32V(8), WASM_I64V(1),
WASM_I64V(memory[1]), MachineRepresentation::kWord64),
WASM_I64V(32))));
CHECK_EQ(0x12345678, r.Call());
}
} // namespace test_run_wasm_atomics_64
} // namespace wasm
} // namespace internal