Commit 0d5b0d73 authored by Martyn Capewell's avatar Martyn Capewell Committed by Commit Bot

[arm64] Enforce restriction on stlxr instructions

The stlxr (store-release exclusive register) instructions in Arm64 have similar
restrictions to Arm's strex instructions - the status register must not alias
the source or address registers.

Enforce this in the assembler and simulator, and modify Turbofan and cctest to
conform to this. Also, make a small improvement to the code generated for
compare and exchange.

This is a port of 44c52f7b.

Bug: 
Change-Id: Ia3a8c39b09c5cb579357a5f61c3d88f13d61b724
Reviewed-on: https://chromium-review.googlesource.com/793037Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Martyn Capewell <martyn.capewell@arm.com>
Cr-Commit-Position: refs/heads/master@{#49714}
parent 23ccfa1d
......@@ -1758,6 +1758,7 @@ void Assembler::stlxr(const Register& rs, const Register& rt,
const Register& rn) {
DCHECK(rs.Is32Bits());
DCHECK(rn.Is64Bits());
DCHECK(!rs.Is(rt) && !rs.Is(rn));
LoadStoreAcquireReleaseOp op = rt.Is32Bits() ? STLXR_w : STLXR_x;
Emit(op | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
}
......@@ -1785,6 +1786,7 @@ void Assembler::stlxrb(const Register& rs, const Register& rt,
DCHECK(rs.Is32Bits());
DCHECK(rt.Is32Bits());
DCHECK(rn.Is64Bits());
DCHECK(!rs.Is(rt) && !rs.Is(rn));
Emit(STLXR_b | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
}
......@@ -1811,6 +1813,7 @@ void Assembler::stlxrh(const Register& rs, const Register& rt,
DCHECK(rs.Is32Bits());
DCHECK(rt.Is32Bits());
DCHECK(rn.Is64Bits());
DCHECK(!rs.Is(rt) && !rs.Is(rn));
Emit(STLXR_h | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt));
}
......
......@@ -2282,6 +2282,8 @@ void Simulator::VisitLoadStoreAcquireRelease(Instruction* instr) {
} else {
if (is_exclusive) {
unsigned rs = instr->Rs();
DCHECK_NE(rs, rt);
DCHECK_NE(rs, rn);
if (local_monitor_.NotifyStoreExcl(address,
get_transaction_size(access_size)) &&
global_monitor_.Pointer()->NotifyStoreExcl_Locked(
......
......@@ -528,40 +528,40 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \
do { \
Label exchange; \
__ bind(&exchange); \
__ Add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ Bind(&exchange); \
__ load_instr(i.OutputRegister32(), i.TempRegister(0)); \
__ store_instr(i.TempRegister32(0), i.InputRegister32(2), \
__ store_instr(i.TempRegister32(1), i.InputRegister32(2), \
i.TempRegister(0)); \
__ cbnz(i.TempRegister32(0), &exchange); \
__ Cbnz(i.TempRegister32(1), &exchange); \
} while (0)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr) \
do { \
Label compareExchange; \
Label exit; \
__ bind(&compareExchange); \
__ Add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ load_instr(i.OutputRegister32(), i.TempRegister(0)); \
__ cmp(i.TempRegister32(1), i.OutputRegister32()); \
__ B(ne, &exit); \
__ store_instr(i.TempRegister32(0), i.InputRegister32(3), \
i.TempRegister(0)); \
__ cbnz(i.TempRegister32(0), &compareExchange); \
__ bind(&exit); \
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr, ext) \
do { \
Label compareExchange; \
Label exit; \
__ Add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ Bind(&compareExchange); \
__ load_instr(i.OutputRegister32(), i.TempRegister(0)); \
__ Cmp(i.OutputRegister32(), Operand(i.InputRegister32(2), ext)); \
__ B(ne, &exit); \
__ store_instr(i.TempRegister32(1), i.InputRegister32(3), \
i.TempRegister(0)); \
__ Cbnz(i.TempRegister32(1), &compareExchange); \
__ Bind(&exit); \
} while (0)
#define ASSEMBLE_ATOMIC_BINOP(load_instr, store_instr, bin_instr) \
do { \
Label binop; \
__ Add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ bind(&binop); \
__ Bind(&binop); \
__ load_instr(i.OutputRegister32(), i.TempRegister(0)); \
__ bin_instr(i.TempRegister32(1), i.OutputRegister32(), \
Operand(i.InputRegister32(2))); \
__ store_instr(i.TempRegister32(1), i.TempRegister32(1), \
__ store_instr(i.TempRegister32(2), i.TempRegister32(1), \
i.TempRegister(0)); \
__ cbnz(i.TempRegister32(1), &binop); \
__ Cbnz(i.TempRegister32(2), &binop); \
} while (0)
#define ASSEMBLE_IEEE754_BINOP(name) \
......@@ -1820,26 +1820,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(ldaxr, stlxr);
break;
case kAtomicCompareExchangeInt8:
__ Uxtb(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrb, stlxrb);
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrb, stlxrb, UXTB);
__ Sxtb(i.OutputRegister(0), i.OutputRegister(0));
break;
case kAtomicCompareExchangeUint8:
__ Uxtb(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrb, stlxrb);
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrb, stlxrb, UXTB);
break;
case kAtomicCompareExchangeInt16:
__ Uxth(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrh, stlxrh);
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrh, stlxrh, UXTH);
__ Sxth(i.OutputRegister(0), i.OutputRegister(0));
break;
case kAtomicCompareExchangeUint16:
__ Uxth(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrh, stlxrh);
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxrh, stlxrh, UXTH);
break;
case kAtomicCompareExchangeWord32:
__ mov(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxr, stlxr);
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldaxr, stlxr, UXTW);
break;
#define ATOMIC_BINOP_CASE(op, inst) \
case kAtomic##op##Int8: \
......@@ -1865,6 +1860,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ATOMIC_BINOP_CASE(Or, Orr)
ATOMIC_BINOP_CASE(Xor, Eor)
#undef ATOMIC_BINOP_CASE
#undef ASSEMBLE_BOUNDS_CHECK
#undef ASSEMBLE_CHECKED_LOAD_FLOAT
#undef ASSEMBLE_CHECKED_LOAD_INTEGER
#undef ASSEMBLE_CHECKED_LOAD_INTEGER_64
#undef ASSEMBLE_CHECKED_STORE_FLOAT
#undef ASSEMBLE_CHECKED_STORE_INTEGER
#undef ASSEMBLE_CHECKED_STORE_INTEGER_64
#undef ASSEMBLE_SHIFT
#undef ASSEMBLE_ATOMIC_LOAD_INTEGER
#undef ASSEMBLE_ATOMIC_STORE_INTEGER
#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
#undef ASSEMBLE_ATOMIC_BINOP
#undef ASSEMBLE_IEEE754_BINOP
#undef ASSEMBLE_IEEE754_UNOP
#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER
#define SIMD_UNOP_CASE(Op, Instr, FORMAT) \
case Op: \
......
......@@ -2755,12 +2755,12 @@ void InstructionSelector::VisitAtomicExchange(Node* node) {
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.UseRegister(base);
inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node);
InstructionOperand temps[] = {g.TempRegister()};
outputs[0] = g.DefineAsRegister(node);
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
}
......@@ -2791,17 +2791,15 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
AddressingMode addressing_mode = kMode_MRR;
InstructionOperand inputs[4];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index);
inputs[input_count++] = g.UseRegister(base);
inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(old_value);
inputs[input_count++] = g.UseUniqueRegister(new_value);
InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node);
InstructionOperand temp[2];
temp[0] = g.TempRegister();
temp[1] = g.TempRegister();
outputs[0] = g.DefineAsRegister(node);
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs, 2, temp);
Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
}
void InstructionSelector::VisitAtomicBinaryOperation(
......@@ -2831,16 +2829,15 @@ void InstructionSelector::VisitAtomicBinaryOperation(
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.UseRegister(base);
inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node);
InstructionOperand temps[2];
temps[0] = g.TempRegister();
temps[1] = g.TempRegister();
outputs[0] = g.DefineAsRegister(node);
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
g.TempRegister()};
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs, 2, temps);
Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
}
#define VISIT_ATOMIC_BINOP(op) \
......
......@@ -1490,9 +1490,9 @@ TEST_(load_store_acquire_release) {
COMPARE(ldaxrb(wzr, csp), "ldaxrb wzr, [csp]");
COMPARE(ldaxrh(wzr, csp), "ldaxrh wzr, [csp]");
COMPARE(ldaxr(wzr, csp), "ldaxr wzr, [csp]");
COMPARE(stlxrb(wzr, wzr, csp), "stlxrb wzr, wzr, [csp]");
COMPARE(stlxrh(wzr, wzr, csp), "stlxrh wzr, wzr, [csp]");
COMPARE(stlxr(wzr, wzr, csp), "stlxr wzr, wzr, [csp]");
COMPARE(stlxrb(w0, wzr, csp), "stlxrb w0, wzr, [csp]");
COMPARE(stlxrh(wzr, w1, csp), "stlxrh wzr, w1, [csp]");
COMPARE(stlxr(w2, wzr, csp), "stlxr w2, wzr, [csp]");
CLEANUP();
}
......
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