Commit f5d6ea17 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[ia32,root] Fix atomic operations to not reference ebx

This is a hack to make sure the atomic operations don't
use the kRootRegister ebx before code generation.

I've filed v8:8254 to track that a larger clean-up operation
will be needed to remove this and other hacks.

Change-Id: I6f28f01ba2f96257a9e65eaa36fcad66b01906dd
Bug: v8:6666, v8:8254
Reviewed-on: https://chromium-review.googlesource.com/c/1256862Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56366}
parent 19594301
......@@ -430,21 +430,30 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
__ j(not_equal, &binop); \
} while (false)
#define ASSEMBLE_I64ATOMIC_BINOP(instr1, instr2) \
do { \
Label binop; \
__ bind(&binop); \
__ mov(eax, i.MemoryOperand(2)); \
__ mov(edx, i.NextMemoryOperand(2)); \
__ push(i.InputRegister(0)); \
__ push(i.InputRegister(1)); \
__ instr1(i.InputRegister(0), eax); \
__ instr2(i.InputRegister(1), edx); \
__ lock(); \
__ cmpxchg8b(i.MemoryOperand(2)); \
__ pop(i.InputRegister(1)); \
__ pop(i.InputRegister(0)); \
__ j(not_equal, &binop); \
#define ASSEMBLE_I64ATOMIC_BINOP(instr1, instr2) \
do { \
Label binop; \
__ bind(&binop); \
TurboAssembler::AllowExplicitEbxAccessScope spill_register(tasm()); \
__ mov(eax, i.MemoryOperand(2)); \
__ mov(edx, i.NextMemoryOperand(2)); \
__ push(ebx); \
frame_access_state()->IncreaseSPDelta(1); \
InstructionOperand* op = instr->InputAt(0); \
if (op->IsImmediate() || op->IsConstant()) { \
__ mov(ebx, i.ToImmediate(op)); \
} else { \
__ mov(ebx, i.ToOperand(op)); \
} \
__ push(i.InputRegister(1)); \
__ instr1(ebx, eax); \
__ instr2(i.InputRegister(1), edx); \
__ lock(); \
__ cmpxchg8b(i.MemoryOperand(2)); \
__ pop(i.InputRegister(1)); \
__ pop(ebx); \
frame_access_state()->IncreaseSPDelta(-1); \
__ j(not_equal, &binop); \
} while (false);
#define ASSEMBLE_MOVX(mov_instr) \
......@@ -3669,10 +3678,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kIA32Word32AtomicPairStore: {
TurboAssembler::AllowExplicitEbxAccessScope spill_register(tasm());
__ mov(i.TempRegister(0), i.MemoryOperand(2));
__ mov(i.TempRegister(1), i.NextMemoryOperand(2));
__ push(ebx);
frame_access_state()->IncreaseSPDelta(1);
InstructionOperand* op = instr->InputAt(0);
if (op->IsImmediate() || op->IsConstant()) {
__ mov(ebx, i.ToImmediate(op));
} else {
__ mov(ebx, i.ToOperand(op));
}
__ lock();
__ cmpxchg8b(i.MemoryOperand(2));
__ pop(ebx);
frame_access_state()->IncreaseSPDelta(-1);
break;
}
case kWord32AtomicExchangeInt8: {
......@@ -3701,10 +3721,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kIA32Word32AtomicPairExchange: {
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr));
TurboAssembler::AllowExplicitEbxAccessScope spill_ebx(tasm());
__ mov(eax, i.MemoryOperand(2));
__ mov(edx, i.NextMemoryOperand(2));
__ push(ebx);
frame_access_state()->IncreaseSPDelta(1);
InstructionOperand* op = instr->InputAt(0);
if (op->IsImmediate() || op->IsConstant()) {
__ mov(ebx, i.ToImmediate(op));
} else {
__ mov(ebx, i.ToOperand(op));
}
__ lock();
__ cmpxchg8b(i.MemoryOperand(2));
__ pop(ebx);
frame_access_state()->IncreaseSPDelta(-1);
break;
}
case kWord32AtomicCompareExchangeInt8: {
......@@ -3737,8 +3768,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kIA32Word32AtomicPairCompareExchange: {
TurboAssembler::AllowExplicitEbxAccessScope spill_ebx(tasm());
__ push(ebx);
frame_access_state()->IncreaseSPDelta(1);
InstructionOperand* op = instr->InputAt(2);
if (op->IsImmediate() || op->IsConstant()) {
__ mov(ebx, i.ToImmediate(op));
} else {
__ mov(ebx, i.ToOperand(op));
}
__ lock();
__ cmpxchg8b(i.MemoryOperand(4));
__ pop(ebx);
frame_access_state()->IncreaseSPDelta(-1);
break;
}
#define ATOMIC_BINOP_CASE(op, inst) \
......@@ -3787,24 +3829,33 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK(VerifyOutputOfAtomicPairInstr(&i, instr));
Label binop;
__ bind(&binop);
TurboAssembler::AllowExplicitEbxAccessScope spill_register(tasm());
// Move memory operand into edx:eax
__ mov(eax, i.MemoryOperand(2));
__ mov(edx, i.NextMemoryOperand(2));
// Save input registers temporarily on the stack.
__ push(i.InputRegister(0));
__ push(ebx);
frame_access_state()->IncreaseSPDelta(1);
InstructionOperand* op = instr->InputAt(0);
if (op->IsImmediate() || op->IsConstant()) {
__ mov(ebx, i.ToImmediate(op));
} else {
__ mov(ebx, i.ToOperand(op));
}
__ push(i.InputRegister(1));
// Negate input in place
__ neg(i.InputRegister(0));
__ neg(ebx);
__ adc(i.InputRegister(1), 0);
__ neg(i.InputRegister(1));
// Add memory operand, negated input.
__ add(i.InputRegister(0), eax);
__ add(ebx, eax);
__ adc(i.InputRegister(1), edx);
__ lock();
__ cmpxchg8b(i.MemoryOperand(2));
// Restore input registers
__ pop(i.InputRegister(1));
__ pop(i.InputRegister(0));
__ pop(ebx);
frame_access_state()->IncreaseSPDelta(-1);
__ j(not_equal, &binop);
break;
}
......
......@@ -1343,31 +1343,41 @@ void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
// For Word64 operations, the value input is split into the a high node,
// and a low node in the int64-lowering phase.
Node* value_high = node->InputAt(3);
#if defined(V8_EMBEDDED_BUILTINS)
bool block_root_register = !selector->CanUseRootsRegister();
#else
bool block_root_register = true;
#endif
// Wasm lives in 32-bit address space, so we do not need to worry about
// base/index lowering. This will need to be fixed for Wasm64.
AddressingMode addressing_mode;
InstructionOperand inputs[] = {
g.UseFixed(value, ebx), g.UseFixed(value_high, ecx),
g.UseUniqueRegisterOrSlotOrConstant(value), g.UseFixed(value_high, ecx),
g.UseUniqueRegister(base),
g.GetEffectiveIndexOperand(index, &addressing_mode)};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Node* projection0 = NodeProperties::FindProjection(node, 0);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand temps[] = {g.TempRegister(ebx)};
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax),
g.DefineAsFixed(projection1, edx)};
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs),
inputs);
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
num_temps, temps);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax)};
InstructionOperand temps[] = {g.TempRegister(edx)};
InstructionOperand temps[] = {g.TempRegister(edx), g.TempRegister(ebx)};
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
num_temps, temps);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
selector->Emit(code, 0, nullptr, arraysize(inputs), inputs,
arraysize(temps), temps);
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx),
g.TempRegister(ebx)};
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
selector->Emit(code, 0, nullptr, arraysize(inputs), inputs, num_temps,
temps);
}
}
......@@ -1787,19 +1797,26 @@ void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
Node* value_high = node->InputAt(3);
#if defined(V8_EMBEDDED_BUILTINS)
bool block_root_register = !CanUseRootsRegister();
#else
bool block_root_register = true;
#endif
AddressingMode addressing_mode;
InstructionOperand inputs[] = {
g.UseFixed(value, ebx), g.UseFixed(value_high, ecx),
g.UseUniqueRegisterOrSlotOrConstant(value), g.UseFixed(value_high, ecx),
g.UseUniqueRegister(base),
g.GetEffectiveIndexOperand(index, &addressing_mode)};
// Allocating temp registers here as stores are performed using an atomic
// exchange, the output of which is stored in edx:eax, which should be saved
// and restored at the end of the instruction.
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx),
g.TempRegister(ebx)};
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
InstructionCode code =
kIA32Word32AtomicPairStore | AddressingModeField::encode(addressing_mode);
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
Emit(code, 0, nullptr, arraysize(inputs), inputs, num_temps, temps);
}
void InstructionSelector::VisitWord32AtomicPairAdd(Node* node) {
......@@ -1830,11 +1847,18 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
IA32OperandGenerator g(this);
Node* index = node->InputAt(1);
AddressingMode addressing_mode;
#if defined(V8_EMBEDDED_BUILTINS)
bool block_root_register = !CanUseRootsRegister();
#else
bool block_root_register = true;
#endif
InstructionOperand inputs[] = {
// High, Low values of old value
g.UseFixed(node->InputAt(2), eax), g.UseFixed(node->InputAt(3), edx),
// High, Low values of new value
g.UseFixed(node->InputAt(4), ebx), g.UseFixed(node->InputAt(5), ecx),
g.UseUniqueRegisterOrSlotOrConstant(node->InputAt(4)),
g.UseFixed(node->InputAt(5), ecx),
// InputAt(0) => base
g.UseUniqueRegister(node->InputAt(0)),
g.GetEffectiveIndexOperand(index, &addressing_mode)};
......@@ -1842,18 +1866,25 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionCode code = kIA32Word32AtomicPairCompareExchange |
AddressingModeField::encode(addressing_mode);
if (projection1) {
InstructionOperand temps[] = {g.TempRegister(ebx)};
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax),
g.DefineAsFixed(projection1, edx)};
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs);
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
num_temps, temps);
} else if (projection0) {
InstructionOperand outputs[] = {g.DefineAsFixed(projection0, eax)};
InstructionOperand temps[] = {g.TempRegister(edx)};
InstructionOperand temps[] = {g.TempRegister(edx), g.TempRegister(ebx)};
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
arraysize(temps), temps);
num_temps, temps);
} else {
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx),
g.TempRegister(ebx)};
const int num_temps = arraysize(temps) - (block_root_register ? 0 : 1);
Emit(code, 0, nullptr, arraysize(inputs), inputs, num_temps, temps);
}
}
......
......@@ -155,6 +155,12 @@ class OperandGenerator {
UnallocatedOperand::USED_AT_START, GetVReg(node)));
}
InstructionOperand UseUniqueRegisterOrSlotOrConstant(Node* node) {
return Use(node, UnallocatedOperand(
UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT,
GetVReg(node)));
}
InstructionOperand UseRegister(Node* node) {
return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
UnallocatedOperand::USED_AT_START,
......
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