Commit 95f210d5 authored by martyn.capewell's avatar martyn.capewell Committed by Commit bot

[turbofan] ARM64: Faster checked ops for PoT arrays

Improve CheckedLoad and Store bounds checking for arrays with power of two
length.

BUG=

Review-Url: https://codereview.chromium.org/2043663002
Cr-Commit-Position: refs/heads/master@{#36756}
parent 4cc1331c
......@@ -400,6 +400,17 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
} // namespace
#define ASSEMBLE_BOUNDS_CHECK(offset, length, out_of_bounds) \
do { \
if (length.IsImmediate() && \
base::bits::IsPowerOfTwo64(length.ImmediateValue())) { \
__ Tst(offset, ~(length.ImmediateValue() - 1)); \
__ B(ne, out_of_bounds); \
} else { \
__ Cmp(offset, length); \
__ B(hs, out_of_bounds); \
} \
} while (0)
#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \
do { \
......@@ -407,37 +418,32 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
__ Cmp(offset, length); \
auto ool = new (zone()) OutOfLineLoadNaN##width(this, result); \
__ B(hs, ool->entry()); \
ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry()); \
__ Ldr(result, MemOperand(buffer, offset, UXTW)); \
__ Bind(ool->exit()); \
} while (0)
#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
do { \
auto result = i.OutputRegister32(); \
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
__ Cmp(offset, length); \
auto ool = new (zone()) OutOfLineLoadZero(this, result); \
__ B(hs, ool->entry()); \
ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry()); \
__ asm_instr(result, MemOperand(buffer, offset, UXTW)); \
__ Bind(ool->exit()); \
} while (0)
#define ASSEMBLE_CHECKED_LOAD_INTEGER_64(asm_instr) \
do { \
auto result = i.OutputRegister(); \
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
__ Cmp(offset, length); \
auto ool = new (zone()) OutOfLineLoadZero(this, result); \
__ B(hs, ool->entry()); \
ASSEMBLE_BOUNDS_CHECK(offset, length, ool->entry()); \
__ asm_instr(result, MemOperand(buffer, offset, UXTW)); \
__ Bind(ool->exit()); \
} while (0)
......@@ -448,9 +454,8 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputFloat##width##OrZeroRegister(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
ASSEMBLE_BOUNDS_CHECK(offset, length, &done); \
__ Str(value, MemOperand(buffer, offset, UXTW)); \
__ Bind(&done); \
} while (0)
......@@ -461,9 +466,8 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputOrZeroRegister32(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
ASSEMBLE_BOUNDS_CHECK(offset, length, &done); \
__ asm_instr(value, MemOperand(buffer, offset, UXTW)); \
__ Bind(&done); \
} while (0)
......@@ -474,9 +478,8 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputOrZeroRegister64(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
ASSEMBLE_BOUNDS_CHECK(offset, length, &done); \
__ asm_instr(value, MemOperand(buffer, offset, UXTW)); \
__ Bind(&done); \
} while (0)
......
......@@ -593,6 +593,17 @@ void InstructionSelector::VisitCheckedLoad(Node* node) {
UNREACHABLE();
return;
}
// If the length is a constant power of two, allow the code generator to
// pick a more efficient bounds check sequence by passing the length as an
// immediate.
if (length->opcode() == IrOpcode::kInt32Constant) {
Int32Matcher m(length);
if (m.IsPowerOf2()) {
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
g.UseRegister(offset), g.UseImmediate(length));
return;
}
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
g.UseRegister(offset), g.UseOperand(length, kArithmeticImm));
}
......@@ -632,6 +643,17 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
UNREACHABLE();
return;
}
// If the length is a constant power of two, allow the code generator to
// pick a more efficient bounds check sequence by passing the length as an
// immediate.
if (length->opcode() == IrOpcode::kInt32Constant) {
Int32Matcher m(length);
if (m.IsPowerOf2()) {
Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
g.UseImmediate(length), g.UseRegisterOrImmediateZero(value));
return;
}
}
Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
g.UseOperand(length, kArithmeticImm),
g.UseRegisterOrImmediateZero(value));
......
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