[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:
parent
148b53910e
commit
bc436ed752
@ -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) \
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user