Commit e15f5ba1 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

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

The instruction selector assumed for Word32AtomicPairBinop 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: I22331cae58f933e89dac6993fe3b21ff6502838a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2011829Reviewed-by: 's avatarDeepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65941}
parent 9c934d34
......@@ -589,12 +589,20 @@ void AdjustStackPointerForTailCall(
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;
DCHECK_GE(instr->OutputCount() + instr->TempCount(), 2);
if (instr->OutputCount() == 2) {
return (converter->OutputRegister(0) == low &&
converter->OutputRegister(1) == high);
}
if (instr->OutputCount() == 1) {
return (converter->OutputRegister(0) == low &&
converter->TempRegister(instr->TempCount() - 1) == high) ||
(converter->OutputRegister(0) == high &&
converter->TempRegister(instr->TempCount() - 1) == low);
}
DCHECK_EQ(instr->OutputCount(), 0);
return (converter->TempRegister(instr->TempCount() - 2) == low &&
converter->TempRegister(instr->TempCount() - 1) == high);
}
#endif
......
......@@ -427,33 +427,32 @@ void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
Node* value = node->InputAt(2);
Node* value_high = node->InputAt(3);
AddressingMode addressing_mode = kMode_Offset_RR;
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
InstructionOperand inputs[] = {
g.UseUniqueRegister(value), g.UseUniqueRegister(value_high),
g.UseUniqueRegister(base), g.UseUniqueRegister(index)};
InstructionOperand outputs[2];
size_t output_count = 0;
InstructionOperand temps[6];
size_t temp_count = 0;
temps[temp_count++] = g.TempRegister();
temps[temp_count++] = g.TempRegister(r6);
temps[temp_count++] = g.TempRegister(r7);
temps[temp_count++] = g.TempRegister();
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
if (projection0) {
outputs[output_count++] = g.DefineAsFixed(projection0, r2);
} else {
temps[temp_count++] = g.TempRegister(r2);
}
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2),
g.DefineAsFixed(projection1, r3)};
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
g.TempRegister(r7), g.TempRegister()};
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);
outputs[output_count++] = g.DefineAsFixed(projection1, r3);
} 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);
temps[temp_count++] = g.TempRegister(r3);
}
selector->Emit(code, output_count, outputs, arraysize(inputs), inputs,
temp_count, temps);
}
} // namespace
......
......@@ -563,12 +563,19 @@ 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;
if (instr->OutputCount() == 2) {
return (converter->OutputRegister(0) == eax &&
converter->OutputRegister(1) == edx);
}
if (instr->OutputCount() == 1) {
return (converter->OutputRegister(0) == eax &&
converter->TempRegister(0) == edx) ||
(converter->OutputRegister(0) == edx &&
converter->TempRegister(0) == eax);
}
DCHECK_EQ(instr->OutputCount(), 0);
return (converter->TempRegister(0) == eax &&
converter->TempRegister(1) == edx);
}
#endif
......
......@@ -1514,23 +1514,22 @@ void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
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 {
temps[temp_count++] = g.TempRegister(eax);
}
if (projection1) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax),
g.DefineAsFixed(projection1, edx)};
selector->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);
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
num_temps, temps);
outputs[output_count++] = g.DefineAsFixed(projection1, edx);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
const int num_temps = arraysize(temps);
selector->Emit(code, 0, nullptr, arraysize(inputs), inputs, num_temps,
temps);
temps[temp_count++] = g.TempRegister(edx);
}
selector->Emit(code, output_count, outputs, arraysize(inputs), inputs,
temp_count, temps);
}
} // namespace
......
......@@ -723,6 +723,35 @@ WASM_EXEC_TEST(I64AtomicLoadUseOnlyHighWord) {
CHECK_EQ(0x12345678, r.Call());
}
WASM_EXEC_TEST(I64AtomicAddUseOnlyLowWord) {
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_BINOP(kExprI64AtomicAdd, WASM_I32V(8), WASM_I64V(1),
MachineRepresentation::kWord64)));
CHECK_EQ(0x90abcdef, r.Call());
}
WASM_EXEC_TEST(I64AtomicAddUseOnlyHighWord) {
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_BINOP(kExprI64AtomicAdd, WASM_I32V(8), WASM_I64V(1),
MachineRepresentation::kWord64),
WASM_I64V(32))));
CHECK_EQ(0x12345678, r.Call());
}
} // 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