Commit 3c83ffb9 authored by Vasili Skurydzin's avatar Vasili Skurydzin Committed by Commit Bot

PPC/s390: Implement 32-bit atomic operations

Implement atomic compare exchange and atomic bin OPs for
PPC and s390

Change-Id: I8f89a0ebb912082c4c1e6b9a3daf64f28c114010
Reviewed-on: https://chromium-review.googlesource.com/1013861Reviewed-by: 's avatarJunliang Yan <jyan@ca.ibm.com>
Commit-Queue: Junliang Yan <jyan@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#53165}
parent 17875b01
...@@ -659,6 +659,60 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr, ...@@ -659,6 +659,60 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr,
__ bne(&exchange, cr0); \ __ bne(&exchange, cr0); \
} while (0) } while (0)
#define ASSEMBLE_ATOMIC_BINOP(bin_inst, load_inst, store_inst) \
do { \
MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
Label binop; \
__ bind(&binop); \
__ load_inst(i.OutputRegister(), operand); \
__ bin_inst(i.InputRegister(2), i.OutputRegister(), i.InputRegister(2)); \
__ store_inst(i.InputRegister(2), operand); \
__ bne(&binop, cr0); \
} while (false)
#define ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(bin_inst, load_inst, \
store_inst, ext_instr) \
do { \
MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
Label binop; \
__ bind(&binop); \
__ load_inst(i.OutputRegister(), operand); \
__ ext_instr(i.OutputRegister(), i.OutputRegister()); \
__ bin_inst(i.InputRegister(2), i.OutputRegister(), i.InputRegister(2)); \
__ store_inst(i.InputRegister(2), operand); \
__ bne(&binop, cr0); \
} while (false)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp_inst, load_inst, store_inst) \
do { \
MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
Label loop; \
Label exit; \
__ bind(&loop); \
__ load_inst(i.OutputRegister(), operand); \
__ cmp_inst(i.OutputRegister(), i.InputRegister(2)); \
__ bne(&exit, cr0); \
__ store_inst(i.InputRegister(3), operand); \
__ bne(&loop, cr0); \
__ bind(&exit); \
} while (false)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp_inst, load_inst, \
store_inst, ext_instr) \
do { \
MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
Label loop; \
Label exit; \
__ bind(&loop); \
__ load_inst(i.OutputRegister(), operand); \
__ ext_instr(i.OutputRegister(), i.OutputRegister()); \
__ cmp_inst(i.OutputRegister(), i.InputRegister(2)); \
__ bne(&exit, cr0); \
__ store_inst(i.InputRegister(3), operand); \
__ bne(&loop, cr0); \
__ bind(&exit); \
} while (false)
void CodeGenerator::AssembleDeconstructFrame() { void CodeGenerator::AssembleDeconstructFrame() {
__ LeaveFrame(StackFrame::MANUAL); __ LeaveFrame(StackFrame::MANUAL);
} }
...@@ -1959,6 +2013,46 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1959,6 +2013,46 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kWord32AtomicExchangeWord32: case kWord32AtomicExchangeWord32:
ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lwarx, stwcx); ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lwarx, stwcx);
break; break;
case kWord32AtomicCompareExchangeInt8:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lbarx, stbcx, extsb);
break;
case kWord32AtomicCompareExchangeUint8:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lbarx, stbcx);
break;
case kWord32AtomicCompareExchangeInt16:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lharx, sthcx, extsh);
break;
case kWord32AtomicCompareExchangeUint16:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lharx, sthcx);
break;
case kWord32AtomicCompareExchangeWord32:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmpw, lwarx, stwcx);
break;
#define ATOMIC_BINOP_CASE(op, inst) \
case kWord32Atomic##op##Int8: \
ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lbarx, stbcx, extsb); \
break; \
case kWord32Atomic##op##Uint8: \
ASSEMBLE_ATOMIC_BINOP(inst, lbarx, stbcx); \
break; \
case kWord32Atomic##op##Int16: \
ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lharx, sthcx, extsh); \
break; \
case kWord32Atomic##op##Uint16: \
ASSEMBLE_ATOMIC_BINOP(inst, lharx, sthcx); \
break; \
case kWord32Atomic##op##Word32: \
ASSEMBLE_ATOMIC_BINOP(inst, lwarx, stwcx); \
break;
ATOMIC_BINOP_CASE(Add, add)
ATOMIC_BINOP_CASE(Sub, sub)
ATOMIC_BINOP_CASE(And, and_)
ATOMIC_BINOP_CASE(Or, orx)
ATOMIC_BINOP_CASE(Xor, xor_)
#undef ATOMIC_BINOP_CASE
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -1995,18 +1995,100 @@ void InstructionSelector::VisitWord32AtomicExchange(Node* node) { ...@@ -1995,18 +1995,100 @@ void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
} }
void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) { void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
UNIMPLEMENTED(); PPCOperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* old_value = node->InputAt(2);
Node* new_value = node->InputAt(3);
MachineType type = AtomicOpRepresentationOf(node->op());
ArchOpcode opcode = kArchNop;
if (type == MachineType::Int8()) {
opcode = kWord32AtomicCompareExchangeInt8;
} else if (type == MachineType::Uint8()) {
opcode = kWord32AtomicCompareExchangeUint8;
} else if (type == MachineType::Int16()) {
opcode = kWord32AtomicCompareExchangeInt16;
} else if (type == MachineType::Uint16()) {
opcode = kWord32AtomicCompareExchangeUint16;
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
opcode = kWord32AtomicCompareExchangeWord32;
} else {
UNREACHABLE();
return;
}
AddressingMode addressing_mode = kMode_MRR;
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
InstructionOperand inputs[4];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index);
inputs[input_count++] = g.UseUniqueRegister(old_value);
inputs[input_count++] = g.UseUniqueRegister(new_value);
InstructionOperand outputs[1];
size_t output_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
Emit(code, output_count, outputs, input_count, inputs);
} }
void InstructionSelector::VisitWord32AtomicAdd(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitWord32AtomicBinaryOperation(
Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
ArchOpcode uint16_op, ArchOpcode word32_op) {
PPCOperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
MachineType type = AtomicOpRepresentationOf(node->op());
ArchOpcode opcode = kArchNop;
void InstructionSelector::VisitWord32AtomicSub(Node* node) { UNIMPLEMENTED(); } if (type == MachineType::Int8()) {
opcode = int8_op;
} else if (type == MachineType::Uint8()) {
opcode = uint8_op;
} else if (type == MachineType::Int16()) {
opcode = int16_op;
} else if (type == MachineType::Uint16()) {
opcode = uint16_op;
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
opcode = word32_op;
} else {
UNREACHABLE();
return;
}
AddressingMode addressing_mode = kMode_MRR;
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
InstructionOperand inputs[3];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value);
void InstructionSelector::VisitWord32AtomicAnd(Node* node) { UNIMPLEMENTED(); } InstructionOperand outputs[1];
size_t output_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
void InstructionSelector::VisitWord32AtomicOr(Node* node) { UNIMPLEMENTED(); } Emit(code, output_count, outputs, input_count, inputs);
}
#define VISIT_ATOMIC_BINOP(op) \
void InstructionSelector::VisitWord32Atomic##op(Node* node) { \
VisitWord32AtomicBinaryOperation( \
node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \
kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16, \
kWord32Atomic##op##Word32); \
}
VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)
VISIT_ATOMIC_BINOP(And)
VISIT_ATOMIC_BINOP(Or)
VISIT_ATOMIC_BINOP(Xor)
#undef VISIT_ATOMIC_BINOP
void InstructionSelector::VisitWord32AtomicXor(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) { void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE(); UNREACHABLE();
......
...@@ -896,6 +896,262 @@ static inline int AssembleUnaryOp(Instruction* instr, _R _r, _M _m, _I _i) { ...@@ -896,6 +896,262 @@ static inline int AssembleUnaryOp(Instruction* instr, _R _r, _M _m, _I _i) {
__ asm_instr(value, operand); \ __ asm_instr(value, operand); \
} while (0) } while (0)
#define ATOMIC_COMP_EXCHANGE(start, end, shift_amount, offset) \
{ \
__ LoadlW(temp0, MemOperand(addr, offset)); \
__ llgfr(temp1, temp0); \
__ risbg(temp0, old_val, Operand(start), Operand(end), \
Operand(shift_amount), false); \
__ risbg(temp1, new_val, Operand(start), Operand(end), \
Operand(shift_amount), false); \
__ CmpAndSwap(temp0, temp1, MemOperand(addr, offset)); \
__ risbg(output, temp0, Operand(start+shift_amount), \
Operand(end+shift_amount), Operand(64-shift_amount), true); \
}
#ifdef V8_TARGET_BIG_ENDIAN
#define ATOMIC_COMP_EXCHANGE_BYTE(i) \
{ \
constexpr int idx = (i); \
static_assert(idx <= 3 && idx >= 0, "idx is out of range!"); \
constexpr int start = 32 + 8 * idx; \
constexpr int end = start + 7; \
constexpr int shift_amount = (3 - idx) * 8; \
ATOMIC_COMP_EXCHANGE(start, end, shift_amount, -idx); \
}
#define ATOMIC_COMP_EXCHANGE_HALFWORD(i) \
{ \
constexpr int idx = (i); \
static_assert(idx <= 1 && idx >= 0, "idx is out of range!"); \
constexpr int start = 32 + 16 * idx; \
constexpr int end = start + 15; \
constexpr int shift_amount = (1 - idx) * 16; \
ATOMIC_COMP_EXCHANGE(start, end, shift_amount, -idx * 2); \
}
#else
#define ATOMIC_COMP_EXCHANGE_BYTE(i) \
{ \
constexpr int idx = (i); \
static_assert(idx <= 3 && idx >= 0, "idx is out of range!"); \
constexpr int start = 32 + 8 * (3 - idx); \
constexpr int end = start + 7; \
constexpr int shift_amount = idx * 8; \
ATOMIC_COMP_EXCHANGE(start, end, shift_amount, -idx); \
}
#define ATOMIC_COMP_EXCHANGE_HALFWORD(i) \
{ \
constexpr int idx = (i); \
static_assert(idx <= 1 && idx >= 0, "idx is out of range!"); \
constexpr int start = 32 + 16 * (1 - idx); \
constexpr int end = start + 15; \
constexpr int shift_amount = idx * 16; \
ATOMIC_COMP_EXCHANGE(start, end, shift_amount, -idx * 2); \
}
#endif
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_BYTE(load_and_ext) \
do { \
Register old_val = i.InputRegister(0); \
Register new_val = i.InputRegister(1); \
Register output = i.OutputRegister(); \
Register addr = kScratchReg; \
Register temp0 = r0; \
Register temp1 = r1; \
size_t index = 2; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode, &index); \
Label three, two, one, done; \
__ lay(addr, op); \
__ tmll(addr, Operand(3)); \
__ b(Condition(1), &three); \
__ b(Condition(2), &two); \
__ b(Condition(4), &one); \
/* ending with 0b00 */ \
ATOMIC_COMP_EXCHANGE_BYTE(0); \
__ b(&done); \
/* ending with 0b01 */ \
__ bind(&one); \
ATOMIC_COMP_EXCHANGE_BYTE(1); \
__ b(&done); \
/* ending with 0b10 */ \
__ bind(&two); \
ATOMIC_COMP_EXCHANGE_BYTE(2); \
__ b(&done); \
/* ending with 0b11 */ \
__ bind(&three); \
ATOMIC_COMP_EXCHANGE_BYTE(3); \
__ bind(&done); \
__ load_and_ext(output, output); \
} while (false)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_HALFWORD(load_and_ext) \
do { \
Register old_val = i.InputRegister(0); \
Register new_val = i.InputRegister(1); \
Register output = i.OutputRegister(); \
Register addr = kScratchReg; \
Register temp0 = r0; \
Register temp1 = r1; \
size_t index = 2; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode, &index); \
Label two, done; \
__ lay(addr, op); \
__ tmll(addr, Operand(3)); \
__ b(Condition(2), &two); \
ATOMIC_COMP_EXCHANGE_HALFWORD(0); \
__ b(&done); \
__ bind(&two); \
ATOMIC_COMP_EXCHANGE_HALFWORD(1); \
__ bind(&done); \
__ load_and_ext(output, output); \
} while (false)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_WORD() \
do { \
Register new_val = i.InputRegister(1); \
Register output = i.OutputRegister(); \
Register addr = kScratchReg; \
size_t index = 2; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode, &index); \
__ lay(addr, op); \
__ CmpAndSwap(output, new_val, MemOperand(addr)); \
} while (false)
// TODO(vasili.skurydzin): use immediate operand for value and
// SI-formatted instructions (i.e. ASI/AGSI for add) to update
// memory atomically
#define ASSEMBLE_ATOMIC_BINOP_WORD(bin_inst, load_and_ext) \
do { \
Register value = i.InputRegister(2); \
Register result = i.OutputRegister(0); \
Register addr = r1; \
Register prev = r0; \
Register next = kScratchReg; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode); \
Label do_cs; \
__ lay(addr, op); \
__ l(prev, MemOperand(addr)); \
__ bind(&do_cs); \
__ bin_inst(next, prev, value); \
__ CmpAndSwap(prev, next, MemOperand(addr)); \
__ bne(&do_cs, Label::kNear); \
__ load_and_ext(result, prev); \
} while (false)
#define ATOMIC_BIN_OP(bin_inst, offset, shift_amount, start, end) \
do { \
Label do_cs; \
__ LoadlW(prev, MemOperand(addr, offset)); \
__ bind(&do_cs); \
__ risbg(temp, value, Operand(start), Operand(end), \
Operand(static_cast<intptr_t>(shift_amount)), true); \
__ bin_inst(new_val, prev, temp); \
__ lr(temp, prev); \
__ risbg(temp, new_val, Operand(start), Operand(end), \
Operand::Zero(), false); \
__ CmpAndSwap(prev, temp, MemOperand(addr, offset)); \
__ bne(&do_cs, Label::kNear); \
} while (false)
#ifdef V8_TARGET_BIG_ENDIAN
#define ATOMIC_BIN_OP_HALFWORD(bin_inst, index, extract_result) \
{ \
constexpr int offset = -(2 * index); \
constexpr int shift_amount = 16 - (index * 16); \
constexpr int start = 48 - shift_amount; \
constexpr int end = start + 15; \
ATOMIC_BIN_OP(bin_inst, offset, shift_amount, start, end); \
extract_result(); \
}
#define ATOMIC_BIN_OP_BYTE(bin_inst, index, extract_result) \
{ \
constexpr int offset = -(index); \
constexpr int shift_amount = 24 - (index * 8); \
constexpr int start = 56 - shift_amount; \
constexpr int end = start + 7; \
ATOMIC_BIN_OP(bin_inst, offset, shift_amount, start, end); \
extract_result(); \
}
#else
#define ATOMIC_BIN_OP_HALFWORD(bin_inst, index, extract_result) \
{ \
constexpr int offset = -(2 * index); \
constexpr int shift_amount = index * 16; \
constexpr int start = 48 - shift_amount; \
constexpr int end = start + 15; \
ATOMIC_BIN_OP(bin_inst, offset, shift_amount, start, end); \
extract_result(); \
}
#define ATOMIC_BIN_OP_BYTE(bin_inst, index, extract_result) \
{ \
constexpr int offset = -(index); \
constexpr int shift_amount = index * 8; \
constexpr int start = 56 - shift_amount; \
constexpr int end = start + 7; \
ATOMIC_BIN_OP(bin_inst, offset, shift_amount, start, end); \
extract_result(); \
}
#endif // V8_TARGET_BIG_ENDIAN
#define ASSEMBLE_ATOMIC_BINOP_HALFWORD(bin_inst, extract_result) \
do { \
Register value = i.InputRegister(2); \
Register result = i.OutputRegister(0); \
Register prev = i.TempRegister(0); \
Register new_val = r0; \
Register addr = r1; \
Register temp = kScratchReg; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode); \
Label two, done; \
__ lay(addr, op); \
__ tmll(addr, Operand(3)); \
__ b(Condition(2), &two); \
/* word boundary */ \
ATOMIC_BIN_OP_HALFWORD(bin_inst, 0, extract_result); \
__ b(&done); \
__ bind(&two); \
/* halfword boundary */ \
ATOMIC_BIN_OP_HALFWORD(bin_inst, 1, extract_result); \
__ bind(&done); \
} while (false)
#define ASSEMBLE_ATOMIC_BINOP_BYTE(bin_inst, extract_result) \
do { \
Register value = i.InputRegister(2); \
Register result = i.OutputRegister(0); \
Register addr = i.TempRegister(0); \
Register prev = r0; \
Register new_val = r1; \
Register temp = kScratchReg; \
AddressingMode mode = kMode_None; \
MemOperand op = i.MemoryOperand(&mode); \
Label done, one, two, three; \
__ lay(addr, op); \
__ tmll(addr, Operand(3)); \
__ b(Condition(1), &three); \
__ b(Condition(2), &two); \
__ b(Condition(4), &one); \
/* ending with 0b00 (word boundary) */ \
ATOMIC_BIN_OP_BYTE(bin_inst, 0, extract_result); \
__ b(&done); \
/* ending with 0b01 */ \
__ bind(&one); \
ATOMIC_BIN_OP_BYTE(bin_inst, 1, extract_result); \
__ b(&done); \
/* ending with 0b10 (hw boundary) */ \
__ bind(&two); \
ATOMIC_BIN_OP_BYTE(bin_inst, 2, extract_result); \
__ b(&done); \
/* ending with 0b11 */ \
__ bind(&three); \
ATOMIC_BIN_OP_BYTE(bin_inst, 3, extract_result); \
__ bind(&done); \
} while (false)
void CodeGenerator::AssembleDeconstructFrame() { void CodeGenerator::AssembleDeconstructFrame() {
__ LeaveFrame(StackFrame::MANUAL); __ LeaveFrame(StackFrame::MANUAL);
} }
...@@ -2298,7 +2554,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2298,7 +2554,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
#define ATOMIC_EXCHANGE(start, end, shift_amount, offset) \ #define ATOMIC_EXCHANGE(start, end, shift_amount, offset) \
{ \ { \
Label do_cs; \ Label do_cs; \
__ LoadlW(output, MemOperand(r1)); \ __ LoadlW(output, MemOperand(r1, offset)); \
__ bind(&do_cs); \ __ bind(&do_cs); \
__ llgfr(r0, output); \ __ llgfr(r0, output); \
__ risbg(r0, value, Operand(start), Operand(end), Operand(shift_amount), \ __ risbg(r0, value, Operand(start), Operand(end), Operand(shift_amount), \
...@@ -2425,6 +2681,60 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2425,6 +2681,60 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ bne(&do_cs, Label::kNear); __ bne(&do_cs, Label::kNear);
break; break;
} }
case kWord32AtomicCompareExchangeInt8:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_BYTE(LoadB);
break;
case kWord32AtomicCompareExchangeUint8:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_BYTE(LoadlB);
break;
case kWord32AtomicCompareExchangeInt16:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_HALFWORD(LoadHalfWordP);
break;
case kWord32AtomicCompareExchangeUint16:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_HALFWORD(LoadLogicalHalfWordP);
break;
case kWord32AtomicCompareExchangeWord32:
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_WORD();
break;
#define ATOMIC_BINOP_CASE(op, inst) \
case kWord32Atomic##op##Int8: \
ASSEMBLE_ATOMIC_BINOP_BYTE(inst, [&]() { \
intptr_t shift_right = static_cast<intptr_t>(shift_amount); \
__ srlk(result, prev, Operand(shift_right)); \
__ LoadB(result, result); \
}); \
break; \
case kWord32Atomic##op##Uint8: \
ASSEMBLE_ATOMIC_BINOP_BYTE(inst, [&]() { \
int rotate_left = shift_amount == 0 ? 0 : 64 - shift_amount; \
__ risbg(result, prev, Operand(56), Operand(63), \
Operand(static_cast<intptr_t>(rotate_left)), true); \
}); \
break; \
case kWord32Atomic##op##Int16: \
ASSEMBLE_ATOMIC_BINOP_HALFWORD(inst, [&]() { \
intptr_t shift_right = static_cast<intptr_t>(shift_amount); \
__ srlk(result, prev, Operand(shift_right)); \
__ LoadHalfWordP(result, result); \
}); \
break; \
case kWord32Atomic##op##Uint16: \
ASSEMBLE_ATOMIC_BINOP_HALFWORD(inst, [&]() { \
int rotate_left = shift_amount == 0 ? 0 : 64 - shift_amount; \
__ risbg(result, prev, Operand(48), Operand(63), \
Operand(static_cast<intptr_t>(rotate_left)), true); \
}); \
break; \
case kWord32Atomic##op##Word32: \
ASSEMBLE_ATOMIC_BINOP_WORD(inst, LoadlW); \
break;
ATOMIC_BINOP_CASE(Add, Add32)
ATOMIC_BINOP_CASE(Sub, Sub32)
ATOMIC_BINOP_CASE(And, And)
ATOMIC_BINOP_CASE(Or, Or)
ATOMIC_BINOP_CASE(Xor, Xor)
#undef ATOMIC_BINOP_CASE
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -2268,24 +2268,124 @@ void InstructionSelector::VisitWord32AtomicExchange(Node* node) { ...@@ -2268,24 +2268,124 @@ void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
inputs[input_count++] = g.UseUniqueRegister(index); inputs[input_count++] = g.UseUniqueRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value); inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1]; InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node); outputs[0] = g.DefineAsRegister(node);
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs); Emit(code, 1, outputs, input_count, inputs);
} }
void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) { void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
UNIMPLEMENTED(); S390OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* old_value = node->InputAt(2);
Node* new_value = node->InputAt(3);
MachineType type = AtomicOpRepresentationOf(node->op());
ArchOpcode opcode = kArchNop;
if (type == MachineType::Int8()) {
opcode = kWord32AtomicCompareExchangeInt8;
} else if (type == MachineType::Uint8()) {
opcode = kWord32AtomicCompareExchangeUint8;
} else if (type == MachineType::Int16()) {
opcode = kWord32AtomicCompareExchangeInt16;
} else if (type == MachineType::Uint16()) {
opcode = kWord32AtomicCompareExchangeUint16;
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
opcode = kWord32AtomicCompareExchangeWord32;
} else {
UNREACHABLE();
return;
}
InstructionOperand inputs[4];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(old_value);
inputs[input_count++] = g.UseUniqueRegister(new_value);
inputs[input_count++] = g.UseUniqueRegister(base);
AddressingMode addressing_mode;
if (g.CanBeImmediate(index, OperandMode::kInt20Imm)) {
inputs[input_count++] = g.UseImmediate(index);
addressing_mode = kMode_MRI;
} else {
inputs[input_count++] = g.UseUniqueRegister(index);
addressing_mode = kMode_MRR;
}
InstructionOperand outputs[1];
size_t output_count = 0;
outputs[output_count++] = g.DefineSameAsFirst(node);
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, output_count, outputs, input_count, inputs);
} }
void InstructionSelector::VisitWord32AtomicAdd(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitWord32AtomicBinaryOperation(
Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
ArchOpcode uint16_op, ArchOpcode word32_op) {
S390OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
MachineType type = AtomicOpRepresentationOf(node->op());
ArchOpcode opcode = kArchNop;
if (type == MachineType::Int8()) {
opcode = int8_op;
} else if (type == MachineType::Uint8()) {
opcode = uint8_op;
} else if (type == MachineType::Int16()) {
opcode = int16_op;
} else if (type == MachineType::Uint16()) {
opcode = uint16_op;
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
opcode = word32_op;
} else {
UNREACHABLE();
return;
}
InstructionOperand inputs[3];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
void InstructionSelector::VisitWord32AtomicSub(Node* node) { UNIMPLEMENTED(); } AddressingMode addressing_mode;
if (g.CanBeImmediate(index, OperandMode::kInt20Imm)) {
inputs[input_count++] = g.UseImmediate(index);
addressing_mode = kMode_MRI;
} else {
inputs[input_count++] = g.UseUniqueRegister(index);
addressing_mode = kMode_MRR;
}
void InstructionSelector::VisitWord32AtomicAnd(Node* node) { UNIMPLEMENTED(); } inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1];
size_t output_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
void InstructionSelector::VisitWord32AtomicOr(Node* node) { UNIMPLEMENTED(); } InstructionOperand temps[1];
size_t temp_count = 0;
temps[temp_count++] = g.TempRegister();
void InstructionSelector::VisitWord32AtomicXor(Node* node) { UNIMPLEMENTED(); } InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, output_count, outputs, input_count, inputs, temp_count, temps);
}
#define VISIT_ATOMIC_BINOP(op) \
void InstructionSelector::VisitWord32Atomic##op(Node* node) { \
VisitWord32AtomicBinaryOperation( \
node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \
kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16, \
kWord32Atomic##op##Word32); \
}
VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)
VISIT_ATOMIC_BINOP(And)
VISIT_ATOMIC_BINOP(Or)
VISIT_ATOMIC_BINOP(Xor)
#undef VISIT_ATOMIC_BINOP
void InstructionSelector::VisitI32x4Splat(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitI32x4Splat(Node* node) { UNIMPLEMENTED(); }
......
...@@ -3348,6 +3348,16 @@ void TurboAssembler::CmpP(Register dst, const MemOperand& opnd) { ...@@ -3348,6 +3348,16 @@ void TurboAssembler::CmpP(Register dst, const MemOperand& opnd) {
#endif #endif
} }
// Using cs or scy based on the offset
void TurboAssembler::CmpAndSwap(Register old_val, Register new_val,
const MemOperand& opnd) {
if (is_uint12(opnd.offset())) {
cs(old_val, new_val, opnd);
} else {
csy(old_val, new_val, opnd);
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Compare Logical Helpers // Compare Logical Helpers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -4046,6 +4056,14 @@ void TurboAssembler::StoreW(Register src, const MemOperand& mem, ...@@ -4046,6 +4056,14 @@ void TurboAssembler::StoreW(Register src, const MemOperand& mem,
} }
} }
void TurboAssembler::LoadHalfWordP(Register dst, Register src) {
#if V8_TARGET_ARCH_S390X
lghr(dst, src);
#else
lhr(dst, src);
#endif
}
// Loads 16-bits half-word value from memory and sign extends to pointer // Loads 16-bits half-word value from memory and sign extends to pointer
// sized register // sized register
void TurboAssembler::LoadHalfWordP(Register dst, const MemOperand& mem, void TurboAssembler::LoadHalfWordP(Register dst, const MemOperand& mem,
......
...@@ -399,6 +399,7 @@ class TurboAssembler : public Assembler { ...@@ -399,6 +399,7 @@ class TurboAssembler : public Assembler {
void CmpP(Register dst, const Operand& opnd); void CmpP(Register dst, const Operand& opnd);
void Cmp32(Register dst, const MemOperand& opnd); void Cmp32(Register dst, const MemOperand& opnd);
void CmpP(Register dst, const MemOperand& opnd); void CmpP(Register dst, const MemOperand& opnd);
void CmpAndSwap(Register old_val, Register new_val, const MemOperand& opnd);
// Compare Logical // Compare Logical
void CmpLogical32(Register src1, Register src2); void CmpLogical32(Register src1, Register src2);
...@@ -767,6 +768,8 @@ class TurboAssembler : public Assembler { ...@@ -767,6 +768,8 @@ class TurboAssembler : public Assembler {
void StoreW(Register src, const MemOperand& mem, Register scratch = no_reg); void StoreW(Register src, const MemOperand& mem, Register scratch = no_reg);
void LoadHalfWordP(Register dst, Register src);
void LoadHalfWordP(Register dst, const MemOperand& mem, void LoadHalfWordP(Register dst, const MemOperand& mem,
Register scratch = no_reg); Register scratch = no_reg);
......
...@@ -7139,9 +7139,13 @@ EVALUATE(LLGCR) { ...@@ -7139,9 +7139,13 @@ EVALUATE(LLGCR) {
} }
EVALUATE(LLGHR) { EVALUATE(LLGHR) {
UNIMPLEMENTED(); DCHECK_OPCODE(LLGHR);
USE(instr); DECODE_RRE_INSTRUCTION(r1, r2);
return 0; uint64_t r2_val = get_low_register<uint64_t>(r2);
r2_val <<= 48;
r2_val >>= 48;
set_register(r1, r2_val);
return length;
} }
EVALUATE(MLGR) { EVALUATE(MLGR) {
......
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