Commit 9598bb93 authored by jyan's avatar jyan Committed by Commit bot

s390: implement atomic exchange on TF

R=joransiu@ca.ibm.com, bjaideep@ca.ibm.com
BUG=

Review-Url: https://codereview.chromium.org/2743803002
Cr-Commit-Position: refs/heads/master@{#43728}
parent e61add91
...@@ -284,7 +284,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { ...@@ -284,7 +284,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
Node* value_integer = ToInteger(context, value); Node* value_integer = ToInteger(context, value);
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X V8_TARGET_ARCH_PPC
Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer, Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer,
value_integer)); value_integer));
#else #else
......
...@@ -2260,13 +2260,138 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2260,13 +2260,138 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kAtomicStoreWord32: case kAtomicStoreWord32:
__ StoreW(i.InputRegister(0), i.MemoryOperand(NULL, 1)); __ StoreW(i.InputRegister(0), i.MemoryOperand(NULL, 1));
break; break;
// 0x aa bb cc dd
// index = 3..2..1..0
#define ATOMIC_EXCHANGE(start, end, shift_amount, offset) \
{ \
Label do_cs; \
__ LoadlW(output, MemOperand(r1)); \
__ bind(&do_cs); \
__ llgfr(r0, output); \
__ risbg(r0, value, Operand(start), Operand(end), Operand(shift_amount), \
false); \
__ csy(output, r0, MemOperand(r1, offset)); \
__ bne(&do_cs, Label::kNear); \
__ srl(output, Operand(shift_amount)); \
}
#ifdef V8_TARGET_BIG_ENDIAN
#define ATOMIC_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_EXCHANGE(start, end, shift_amount, -idx); \
}
#define ATOMIC_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_EXCHANGE(start, end, shift_amount, -idx * 2); \
}
#else
#define ATOMIC_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_EXCHANGE(start, end, shift_amount, -idx); \
}
#define ATOMIC_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_EXCHANGE(start, end, shift_amount, -idx * 2); \
}
#endif
case kAtomicExchangeInt8: case kAtomicExchangeInt8:
case kAtomicExchangeUint8: case kAtomicExchangeUint8: {
Register base = i.InputRegister(0);
Register index = i.InputRegister(1);
Register value = i.InputRegister(2);
Register output = i.OutputRegister();
Label three, two, one, done;
__ la(r1, MemOperand(base, index));
__ tmll(r1, Operand(3));
__ b(Condition(1), &three);
__ b(Condition(2), &two);
__ b(Condition(4), &one);
// end with 0b00
ATOMIC_EXCHANGE_BYTE(0);
__ b(&done);
// ending with 0b01
__ bind(&one);
ATOMIC_EXCHANGE_BYTE(1);
__ b(&done);
// ending with 0b10
__ bind(&two);
ATOMIC_EXCHANGE_BYTE(2);
__ b(&done);
// ending with 0b11
__ bind(&three);
ATOMIC_EXCHANGE_BYTE(3);
__ bind(&done);
if (opcode == kAtomicExchangeInt8) {
__ lbr(output, output);
} else {
__ llcr(output, output);
}
break;
}
case kAtomicExchangeInt16: case kAtomicExchangeInt16:
case kAtomicExchangeUint16: case kAtomicExchangeUint16: {
case kAtomicExchangeWord32: Register base = i.InputRegister(0);
UNREACHABLE(); Register index = i.InputRegister(1);
Register value = i.InputRegister(2);
Register output = i.OutputRegister();
Label two, unaligned, done;
__ la(r1, MemOperand(base, index));
__ tmll(r1, Operand(3));
__ b(Condition(2), &two);
// end with 0b00
ATOMIC_EXCHANGE_HALFWORD(0);
__ b(&done);
// ending with 0b10
__ bind(&two);
ATOMIC_EXCHANGE_HALFWORD(1);
__ bind(&done);
if (opcode == kAtomicExchangeInt8) {
__ lhr(output, output);
} else {
__ llhr(output, output);
}
break; break;
}
case kAtomicExchangeWord32: {
Register base = i.InputRegister(0);
Register index = i.InputRegister(1);
Register value = i.InputRegister(2);
Register output = i.OutputRegister();
Label do_cs;
__ lay(r1, MemOperand(base, index));
__ LoadlW(output, MemOperand(r1));
__ bind(&do_cs);
__ cs(output, value, MemOperand(r1));
__ bne(&do_cs, Label::kNear);
break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -2517,7 +2517,39 @@ void InstructionSelector::VisitAtomicStore(Node* node) { ...@@ -2517,7 +2517,39 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
inputs); inputs);
} }
void InstructionSelector::VisitAtomicExchange(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitAtomicExchange(Node* node) {
S390OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
ArchOpcode opcode = kArchNop;
MachineType type = AtomicExchangeRepresentationOf(node->op());
if (type == MachineType::Int8()) {
opcode = kAtomicExchangeInt8;
} else if (type == MachineType::Uint8()) {
opcode = kAtomicExchangeUint8;
} else if (type == MachineType::Int16()) {
opcode = kAtomicExchangeInt16;
} else if (type == MachineType::Uint16()) {
opcode = kAtomicExchangeUint16;
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
opcode = kAtomicExchangeWord32;
} else {
UNREACHABLE();
return;
}
AddressingMode addressing_mode = kMode_MRR;
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);
InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node);
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs);
}
// static // static
MachineOperatorBuilder::Flags MachineOperatorBuilder::Flags
......
...@@ -1804,6 +1804,21 @@ void Assembler::lmg(Register r1, Register r2, const MemOperand& src) { ...@@ -1804,6 +1804,21 @@ void Assembler::lmg(Register r1, Register r2, const MemOperand& src) {
rsy_form(LMG, r1, r2, src.rb(), src.offset()); rsy_form(LMG, r1, r2, src.rb(), src.offset());
} }
// 32-bit Compare and Swap
void Assembler::cs(Register r1, Register r2, const MemOperand& src) {
rs_form(CS, r1, r2, src.rb(), src.offset());
}
// 32-bit Compare and Swap
void Assembler::csy(Register r1, Register r2, const MemOperand& src) {
rsy_form(CSY, r1, r2, src.rb(), src.offset());
}
// 64-bit Compare and Swap
void Assembler::csg(Register r1, Register r2, const MemOperand& src) {
rsy_form(CSG, r1, r2, src.rb(), src.offset());
}
// Move integer (32) // Move integer (32)
void Assembler::mvhi(const MemOperand& opnd1, const Operand& i2) { void Assembler::mvhi(const MemOperand& opnd1, const Operand& i2) {
sil_form(MVHI, opnd1.getBaseRegister(), opnd1.getDisplacement(), i2); sil_form(MVHI, opnd1.getBaseRegister(), opnd1.getDisplacement(), i2);
......
...@@ -1063,6 +1063,11 @@ class Assembler : public AssemblerBase { ...@@ -1063,6 +1063,11 @@ class Assembler : public AssemblerBase {
void cliy(const MemOperand& mem, const Operand& imm); void cliy(const MemOperand& mem, const Operand& imm);
void clc(const MemOperand& opnd1, const MemOperand& opnd2, Length length); void clc(const MemOperand& opnd1, const MemOperand& opnd2, Length length);
// Compare and Swap Instructions
void cs(Register r1, Register r2, const MemOperand& src);
void csy(Register r1, Register r2, const MemOperand& src);
void csg(Register r1, Register r2, const MemOperand& src);
// Test Under Mask Instructions // Test Under Mask Instructions
void tm(const MemOperand& mem, const Operand& imm); void tm(const MemOperand& mem, const Operand& imm);
void tmy(const MemOperand& mem, const Operand& imm); void tmy(const MemOperand& mem, const Operand& imm);
......
...@@ -640,6 +640,9 @@ bool Decoder::DecodeFourByte(Instruction* instr) { ...@@ -640,6 +640,9 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
case LM: case LM:
Format(instr, "lm\t'r1,'r2,'d1('r3)"); Format(instr, "lm\t'r1,'r2,'d1('r3)");
break; break;
case CS:
Format(instr, "cs\t'r1,'r2,'d1('r3)");
break;
case SLL: case SLL:
Format(instr, "sll\t'r1,'d1('r3)"); Format(instr, "sll\t'r1,'d1('r3)");
break; break;
...@@ -1208,6 +1211,12 @@ bool Decoder::DecodeSixByte(Instruction* instr) { ...@@ -1208,6 +1211,12 @@ bool Decoder::DecodeSixByte(Instruction* instr) {
case LMG: case LMG:
Format(instr, "lmg\t'r1,'r2,'d2('r3)"); Format(instr, "lmg\t'r1,'r2,'d2('r3)");
break; break;
case CSY:
Format(instr, "csy\t'r1,'r2,'d2('r3)");
break;
case CSG:
Format(instr, "csg\t'r1,'r2,'d2('r3)");
break;
case STMY: case STMY:
Format(instr, "stmy\t'r1,'r2,'d2('r3)"); Format(instr, "stmy\t'r1,'r2,'d2('r3)");
break; break;
......
...@@ -842,6 +842,7 @@ void Simulator::EvalTableInit() { ...@@ -842,6 +842,7 @@ void Simulator::EvalTableInit() {
EvalTable[OI] = &Simulator::Evaluate_OI; EvalTable[OI] = &Simulator::Evaluate_OI;
EvalTable[XI] = &Simulator::Evaluate_XI; EvalTable[XI] = &Simulator::Evaluate_XI;
EvalTable[LM] = &Simulator::Evaluate_LM; EvalTable[LM] = &Simulator::Evaluate_LM;
EvalTable[CS] = &Simulator::Evaluate_CS;
EvalTable[MVCLE] = &Simulator::Evaluate_MVCLE; EvalTable[MVCLE] = &Simulator::Evaluate_MVCLE;
EvalTable[CLCLE] = &Simulator::Evaluate_CLCLE; EvalTable[CLCLE] = &Simulator::Evaluate_CLCLE;
EvalTable[MC] = &Simulator::Evaluate_MC; EvalTable[MC] = &Simulator::Evaluate_MC;
...@@ -6446,7 +6447,7 @@ EVALUATE(RISBG) { ...@@ -6446,7 +6447,7 @@ EVALUATE(RISBG) {
if (!zero_remaining) { if (!zero_remaining) {
// Merged the unselected bits from the original value // Merged the unselected bits from the original value
selected_val = (src_val & ~selection_mask) | selected_val; selected_val = (get_register(r1) & ~selection_mask) | selected_val;
} }
// Condition code is set by treating result as 64-bit signed int // Condition code is set by treating result as 64-bit signed int
...@@ -7811,10 +7812,10 @@ EVALUATE(TMLL) { ...@@ -7811,10 +7812,10 @@ EVALUATE(TMLL) {
mask = 0x80000000u >> leadingZeros; mask = 0x80000000u >> leadingZeros;
if (mask & r1_val) { if (mask & r1_val) {
// leftmost bit is one // leftmost bit is one
condition_reg_ = 0x4; condition_reg_ = 0x2;
} else { } else {
// leftmost bit is zero // leftmost bit is zero
condition_reg_ = 0x2; condition_reg_ = 0x4;
} }
return length; // Done! return length; // Done!
#else #else
...@@ -10499,9 +10500,13 @@ EVALUATE(LLCR) { ...@@ -10499,9 +10500,13 @@ EVALUATE(LLCR) {
} }
EVALUATE(LLHR) { EVALUATE(LLHR) {
UNIMPLEMENTED(); DCHECK_OPCODE(LLHR);
USE(instr); DECODE_RRE_INSTRUCTION(r1, r2);
return 0; uint32_t r2_val = get_low_register<uint32_t>(r2);
r2_val <<= 16;
r2_val >>= 16;
set_low_register(r1, r2_val);
return length;
} }
EVALUATE(MLR) { EVALUATE(MLR) {
...@@ -11979,7 +11984,53 @@ EVALUATE(SLLG) { ...@@ -11979,7 +11984,53 @@ EVALUATE(SLLG) {
return length; return length;
} }
EVALUATE(CS) {
DCHECK_OPCODE(CS);
DECODE_RS_A_INSTRUCTION(r1, r3, rb, d2);
int32_t offset = d2;
int64_t rb_val = (rb == 0) ? 0 : get_register(rb);
intptr_t target_addr = static_cast<intptr_t>(rb_val) + offset;
int32_t r1_val = get_low_register<int32_t>(r1);
int32_t r3_val = get_low_register<int32_t>(r3);
DCHECK((target_addr & 0x3) == 0);
bool is_success = __atomic_compare_exchange_n(
reinterpret_cast<int32_t*>(target_addr), &r1_val, r3_val, true,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
if (!is_success) {
set_low_register(r1, r1_val);
condition_reg_ = 0x4;
} else {
condition_reg_ = 0x8;
}
return length;
}
EVALUATE(CSY) { EVALUATE(CSY) {
DCHECK_OPCODE(CSY);
DECODE_RSY_A_INSTRUCTION(r1, r3, b2, d2);
int32_t offset = d2;
int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
intptr_t target_addr = static_cast<intptr_t>(b2_val) + offset;
int32_t r1_val = get_low_register<int32_t>(r1);
int32_t r3_val = get_low_register<int32_t>(r3);
DCHECK((target_addr & 0x3) == 0);
bool is_success = __atomic_compare_exchange_n(
reinterpret_cast<int32_t*>(target_addr), &r1_val, r3_val, true,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
if (!is_success) {
set_low_register(r1, r1_val);
condition_reg_ = 0x4;
} else {
condition_reg_ = 0x8;
}
return length;
}
EVALUATE(CSG) {
UNIMPLEMENTED(); UNIMPLEMENTED();
USE(instr); USE(instr);
return 0; return 0;
......
...@@ -616,6 +616,7 @@ class Simulator { ...@@ -616,6 +616,7 @@ class Simulator {
EVALUATE(OI); EVALUATE(OI);
EVALUATE(XI); EVALUATE(XI);
EVALUATE(LM); EVALUATE(LM);
EVALUATE(CS);
EVALUATE(MVCLE); EVALUATE(MVCLE);
EVALUATE(CLCLE); EVALUATE(CLCLE);
EVALUATE(MC); EVALUATE(MC);
...@@ -1143,6 +1144,7 @@ class Simulator { ...@@ -1143,6 +1144,7 @@ class Simulator {
EVALUATE(SRLG); EVALUATE(SRLG);
EVALUATE(SLLG); EVALUATE(SLLG);
EVALUATE(CSY); EVALUATE(CSY);
EVALUATE(CSG);
EVALUATE(RLLG); EVALUATE(RLLG);
EVALUATE(RLL); EVALUATE(RLL);
EVALUATE(STMG); EVALUATE(STMG);
......
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