Commit 44c52f7b authored by Ben Smith's avatar Ben Smith Committed by Commit Bot

Enforce restriction on ARM strex{b,h} instruction

The strex (Store Exclusive) instruction has the form:

    strex rd, rt, [rn]

It stores the value in register rt at the address in register rn. If the
store succeeds, then 0 is stored in rd, otherwise 1 is stored. The ARM
manual says that behavior is "unpredictable" if d == n || d == t (i.e.
those registers are aliased).

We were not checking for this behavior in the assembler or simulator,
and as a result were generating output where it occurred. This didn't
always break; the tests we run on ARM hardware run this instruction and
pass.

BUG: chromium:786168

Change-Id: I57fe3a1db406eac96eb04ef2246f6970548d3cf9
Reviewed-on: https://chromium-review.googlesource.com/777777Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMircea Trofin <mtrofin@chromium.org>
Commit-Queue: Ben Smith <binji@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49513}
parent 0cd6166c
...@@ -2152,6 +2152,8 @@ void Assembler::strd(Register src1, Register src2, ...@@ -2152,6 +2152,8 @@ void Assembler::strd(Register src1, Register src2,
void Assembler::ldrex(Register dst, Register src, Condition cond) { void Assembler::ldrex(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.75. // Instruction details available in ARM DDI 0406C.b, A8.8.75.
// cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) // cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
DCHECK(dst != pc);
DCHECK(src != pc);
emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xf9f); emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xf9f);
} }
...@@ -2160,6 +2162,11 @@ void Assembler::strex(Register src1, Register src2, Register dst, ...@@ -2160,6 +2162,11 @@ void Assembler::strex(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.212. // Instruction details available in ARM DDI 0406C.b, A8.8.212.
// cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | // cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0) // Rt(3-0)
DCHECK(dst != pc);
DCHECK(src1 != pc);
DCHECK(src2 != pc);
DCHECK(src1 != dst);
DCHECK(src1 != src2);
emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xf9 * B4 | emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xf9 * B4 |
src2.code()); src2.code());
} }
...@@ -2167,6 +2174,8 @@ void Assembler::strex(Register src1, Register src2, Register dst, ...@@ -2167,6 +2174,8 @@ void Assembler::strex(Register src1, Register src2, Register dst,
void Assembler::ldrexb(Register dst, Register src, Condition cond) { void Assembler::ldrexb(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.76. // Instruction details available in ARM DDI 0406C.b, A8.8.76.
// cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) // cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
DCHECK(dst != pc);
DCHECK(src != pc);
emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 | emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 |
0xf9f); 0xf9f);
} }
...@@ -2176,6 +2185,11 @@ void Assembler::strexb(Register src1, Register src2, Register dst, ...@@ -2176,6 +2185,11 @@ void Assembler::strexb(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.213. // Instruction details available in ARM DDI 0406C.b, A8.8.213.
// cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | // cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0) // Rt(3-0)
DCHECK(dst != pc);
DCHECK(src1 != pc);
DCHECK(src2 != pc);
DCHECK(src1 != dst);
DCHECK(src1 != src2);
emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 | emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 |
0xf9 * B4 | src2.code()); 0xf9 * B4 | src2.code());
} }
...@@ -2183,6 +2197,8 @@ void Assembler::strexb(Register src1, Register src2, Register dst, ...@@ -2183,6 +2197,8 @@ void Assembler::strexb(Register src1, Register src2, Register dst,
void Assembler::ldrexh(Register dst, Register src, Condition cond) { void Assembler::ldrexh(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.78. // Instruction details available in ARM DDI 0406C.b, A8.8.78.
// cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0) // cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
DCHECK(dst != pc);
DCHECK(src != pc);
emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 | emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 |
dst.code() * B12 | 0xf9f); dst.code() * B12 | 0xf9f);
} }
...@@ -2192,6 +2208,11 @@ void Assembler::strexh(Register src1, Register src2, Register dst, ...@@ -2192,6 +2208,11 @@ void Assembler::strexh(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.215. // Instruction details available in ARM DDI 0406C.b, A8.8.215.
// cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) | // cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0) // Rt(3-0)
DCHECK(dst != pc);
DCHECK(src1 != pc);
DCHECK(src2 != pc);
DCHECK(src1 != dst);
DCHECK(src1 != src2);
emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 | emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 |
0xf9 * B4 | src2.code()); 0xf9 * B4 | src2.code());
} }
......
...@@ -2188,6 +2188,8 @@ void Simulator::DecodeType01(Instruction* instr) { ...@@ -2188,6 +2188,8 @@ void Simulator::DecodeType01(Instruction* instr) {
int rd = instr->RdValue(); int rd = instr->RdValue();
int rt = instr->RmValue(); int rt = instr->RmValue();
int rn = instr->RnValue(); int rn = instr->RnValue();
DCHECK_NE(rd, rn);
DCHECK_NE(rd, rt);
int32_t addr = get_register(rn); int32_t addr = get_register(rn);
switch (instr->Bits(22, 21)) { switch (instr->Bits(22, 21)) {
case 0: { case 0: {
......
...@@ -432,51 +432,51 @@ Condition FlagsConditionToCondition(FlagsCondition condition) { ...@@ -432,51 +432,51 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
__ dmb(ISH); \ __ dmb(ISH); \
} while (0) } while (0)
#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \ #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \
do { \ do { \
Label exchange; \ Label exchange; \
__ dmb(ISH); \ __ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ bind(&exchange); \ __ dmb(ISH); \
__ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ __ bind(&exchange); \
__ load_instr(i.OutputRegister(0), i.TempRegister(0)); \ __ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
__ store_instr(i.TempRegister(0), i.InputRegister(2), i.TempRegister(0)); \ __ store_instr(i.TempRegister(0), i.InputRegister(2), i.InputRegister(0)); \
__ teq(i.TempRegister(0), Operand(0)); \ __ teq(i.TempRegister(0), Operand(0)); \
__ b(ne, &exchange); \ __ b(ne, &exchange); \
__ dmb(ISH); \ __ dmb(ISH); \
} while (0) } while (0)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr) \ #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr) \
do { \
Label compareExchange; \
Label exit; \
__ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ dmb(ISH); \
__ bind(&compareExchange); \
__ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
__ teq(i.InputRegister(2), Operand(i.OutputRegister(0))); \
__ b(ne, &exit); \
__ store_instr(i.TempRegister(0), i.InputRegister(3), i.InputRegister(0)); \
__ teq(i.TempRegister(0), Operand(0)); \
__ b(ne, &compareExchange); \
__ bind(&exit); \
__ dmb(ISH); \
} while (0)
#define ASSEMBLE_ATOMIC_BINOP(load_instr, store_instr, bin_instr) \
do { \ do { \
Label compareExchange; \ Label binop; \
Label exit; \ __ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ dmb(ISH); \ __ dmb(ISH); \
__ bind(&compareExchange); \ __ bind(&binop); \
__ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ __ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
__ load_instr(i.OutputRegister(0), i.TempRegister(0)); \ __ bin_instr(i.TempRegister(0), i.OutputRegister(0), \
__ teq(i.TempRegister(1), Operand(i.OutputRegister(0))); \ Operand(i.InputRegister(2))); \
__ b(ne, &exit); \ __ store_instr(i.TempRegister(1), i.TempRegister(0), i.InputRegister(0)); \
__ store_instr(i.TempRegister(0), i.InputRegister(3), i.TempRegister(0)); \ __ teq(i.TempRegister(1), Operand(0)); \
__ teq(i.TempRegister(0), Operand(0)); \ __ b(ne, &binop); \
__ b(ne, &compareExchange); \
__ bind(&exit); \
__ dmb(ISH); \ __ dmb(ISH); \
} while (0) } 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)); \
__ dmb(ISH); \
__ bind(&binop); \
__ load_instr(i.OutputRegister(0), i.TempRegister(0)); \
__ bin_instr(i.TempRegister(1), i.OutputRegister(0), \
Operand(i.InputRegister(2))); \
__ store_instr(i.TempRegister(1), i.TempRegister(1), i.TempRegister(0)); \
__ teq(i.TempRegister(1), Operand(0)); \
__ b(ne, &binop); \
__ dmb(ISH); \
} while (0)
#define ASSEMBLE_IEEE754_BINOP(name) \ #define ASSEMBLE_IEEE754_BINOP(name) \
do { \ do { \
/* TODO(bmeurer): We should really get rid of this special instruction, */ \ /* TODO(bmeurer): We should really get rid of this special instruction, */ \
...@@ -2597,25 +2597,24 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2597,25 +2597,24 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(ldrex, strex); ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(ldrex, strex);
break; break;
case kAtomicCompareExchangeInt8: case kAtomicCompareExchangeInt8:
__ uxtb(i.TempRegister(1), i.InputRegister(2)); __ uxtb(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb); ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb);
__ sxtb(i.OutputRegister(0), i.OutputRegister(0)); __ sxtb(i.OutputRegister(0), i.OutputRegister(0));
break; break;
case kAtomicCompareExchangeUint8: case kAtomicCompareExchangeUint8:
__ uxtb(i.TempRegister(1), i.InputRegister(2)); __ uxtb(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb); ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb);
break; break;
case kAtomicCompareExchangeInt16: case kAtomicCompareExchangeInt16:
__ uxth(i.TempRegister(1), i.InputRegister(2)); __ uxth(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh); ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh);
__ sxth(i.OutputRegister(0), i.OutputRegister(0)); __ sxth(i.OutputRegister(0), i.OutputRegister(0));
break; break;
case kAtomicCompareExchangeUint16: case kAtomicCompareExchangeUint16:
__ uxth(i.TempRegister(1), i.InputRegister(2)); __ uxth(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh); ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh);
break; break;
case kAtomicCompareExchangeWord32: case kAtomicCompareExchangeWord32:
__ mov(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrex, strex); ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrex, strex);
break; break;
#define ATOMIC_BINOP_CASE(op, inst) \ #define ATOMIC_BINOP_CASE(op, inst) \
...@@ -2642,6 +2641,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2642,6 +2641,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ATOMIC_BINOP_CASE(Or, orr) ATOMIC_BINOP_CASE(Or, orr)
ATOMIC_BINOP_CASE(Xor, eor) ATOMIC_BINOP_CASE(Xor, eor)
#undef ATOMIC_BINOP_CASE #undef ATOMIC_BINOP_CASE
#undef ASSEMBLE_CHECKED_LOAD_FP
#undef ASSEMBLE_CHECKED_LOAD_INTEGER
#undef ASSEMBLE_CHECKED_STORE_FP
#undef ASSEMBLE_CHECKED_STORE_INTEGER
#undef ASSEMBLE_ATOMIC_LOAD_INTEGER
#undef ASSEMBLE_ATOMIC_STORE_INTEGER
#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER
#undef ASSEMBLE_ATOMIC_BINOP
#undef ASSEMBLE_IEEE754_BINOP
#undef ASSEMBLE_IEEE754_UNOP
#undef ASSEMBLE_NEON_NARROWING_OP
#undef ASSEMBLE_NEON_PAIRWISE_OP
} }
return kSuccess; return kSuccess;
} // NOLINT(readability/fn_size) } // NOLINT(readability/fn_size)
...@@ -3242,6 +3254,7 @@ void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { ...@@ -3242,6 +3254,7 @@ void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
} }
#undef __ #undef __
#undef kScratchReg
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -2277,10 +2277,10 @@ void InstructionSelector::VisitAtomicExchange(Node* node) { ...@@ -2277,10 +2277,10 @@ void InstructionSelector::VisitAtomicExchange(Node* node) {
InstructionOperand inputs[3]; InstructionOperand inputs[3];
size_t input_count = 0; size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base); inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index); inputs[input_count++] = g.UseRegister(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);
InstructionOperand temp[1]; InstructionOperand temp[1];
temp[0] = g.TempRegister(); temp[0] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
...@@ -2314,16 +2314,15 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) { ...@@ -2314,16 +2314,15 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
InstructionOperand inputs[4]; InstructionOperand inputs[4];
size_t input_count = 0; size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base); inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index); inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(old_value); inputs[input_count++] = g.UseUniqueRegister(old_value);
inputs[input_count++] = g.UseUniqueRegister(new_value); inputs[input_count++] = g.UseUniqueRegister(new_value);
InstructionOperand outputs[1]; InstructionOperand outputs[1];
outputs[0] = g.UseUniqueRegister(node); outputs[0] = g.DefineAsRegister(node);
InstructionOperand temp[2]; InstructionOperand temp[1];
temp[0] = g.TempRegister(); temp[0] = g.TempRegister();
temp[1] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs, 2, temp); Emit(code, 1, outputs, input_count, inputs, 1, temp);
} }
void InstructionSelector::VisitAtomicBinaryOperation( void InstructionSelector::VisitAtomicBinaryOperation(
...@@ -2354,15 +2353,16 @@ void InstructionSelector::VisitAtomicBinaryOperation( ...@@ -2354,15 +2353,16 @@ void InstructionSelector::VisitAtomicBinaryOperation(
InstructionOperand inputs[3]; InstructionOperand inputs[3];
size_t input_count = 0; size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base); inputs[input_count++] = g.UseUniqueRegister(base);
inputs[input_count++] = g.UseUniqueRegister(index); inputs[input_count++] = g.UseRegister(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);
InstructionOperand temps[2]; InstructionOperand temps[2];
temps[0] = g.TempRegister(); size_t temp_count = 0;
temps[1] = g.TempRegister(); temps[temp_count++] = g.TempRegister();
temps[temp_count++] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
Emit(code, 1, outputs, input_count, inputs, 2, temps); Emit(code, 1, outputs, input_count, inputs, temp_count, temps);
} }
#define VISIT_ATOMIC_BINOP(op) \ #define VISIT_ATOMIC_BINOP(op) \
......
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