Commit 0322c20d authored by martyn.capewell's avatar martyn.capewell Committed by Commit bot

[turbofan] ARM64: Use zr to store immediate zero

When storing an immediate integer or floating point zero, use the zero register
as the source value. This avoids the need to sometimes allocate a new register.

BUG=

Review-Url: https://codereview.chromium.org/1945783002
Cr-Commit-Position: refs/heads/master@{#36013}
parent 9622696b
......@@ -33,6 +33,24 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
return InputDoubleRegister(index);
}
CPURegister InputFloat32OrZeroRegister(size_t index) {
if (instr_->InputAt(index)->IsImmediate()) {
DCHECK(bit_cast<int32_t>(InputFloat32(index)) == 0);
return wzr;
}
DCHECK(instr_->InputAt(index)->IsDoubleRegister());
return InputDoubleRegister(index).S();
}
CPURegister InputFloat64OrZeroRegister(size_t index) {
if (instr_->InputAt(index)->IsImmediate()) {
DCHECK(bit_cast<int64_t>(InputDouble(index)) == 0);
return xzr;
}
DCHECK(instr_->InputAt(index)->IsDoubleRegister());
return InputDoubleRegister(index);
}
size_t OutputCount() { return instr_->OutputCount(); }
DoubleRegister OutputFloat32Register() { return OutputDoubleRegister().S(); }
......@@ -416,27 +434,25 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
__ Bind(ool->exit()); \
} while (0)
#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \
do { \
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputFloat##width##Register(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
__ Str(value, MemOperand(buffer, offset, UXTW)); \
__ Bind(&done); \
#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \
do { \
auto buffer = i.InputRegister(0); \
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); \
__ Str(value, MemOperand(buffer, offset, UXTW)); \
__ Bind(&done); \
} while (0)
#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
do { \
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputRegister32(3); \
auto value = i.InputOrZeroRegister32(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
......@@ -444,13 +460,12 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
__ Bind(&done); \
} while (0)
#define ASSEMBLE_CHECKED_STORE_INTEGER_64(asm_instr) \
do { \
auto buffer = i.InputRegister(0); \
auto offset = i.InputRegister32(1); \
auto length = i.InputOperand32(2); \
auto value = i.InputRegister(3); \
auto value = i.InputOrZeroRegister64(3); \
__ Cmp(offset, length); \
Label done; \
__ B(hs, &done); \
......@@ -458,7 +473,6 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
__ Bind(&done); \
} while (0)
#define ASSEMBLE_SHIFT(asm_instr, width) \
do { \
if (instr->InputAt(1)->IsRegister()) { \
......@@ -1345,7 +1359,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Ldrsb(i.OutputRegister(), i.MemoryOperand());
break;
case kArm64Strb:
__ Strb(i.InputRegister(2), i.MemoryOperand());
__ Strb(i.InputOrZeroRegister64(2), i.MemoryOperand());
break;
case kArm64Ldrh:
__ Ldrh(i.OutputRegister(), i.MemoryOperand());
......@@ -1354,31 +1368,31 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Ldrsh(i.OutputRegister(), i.MemoryOperand());
break;
case kArm64Strh:
__ Strh(i.InputRegister(2), i.MemoryOperand());
__ Strh(i.InputOrZeroRegister64(2), i.MemoryOperand());
break;
case kArm64LdrW:
__ Ldr(i.OutputRegister32(), i.MemoryOperand());
break;
case kArm64StrW:
__ Str(i.InputRegister32(2), i.MemoryOperand());
__ Str(i.InputOrZeroRegister32(2), i.MemoryOperand());
break;
case kArm64Ldr:
__ Ldr(i.OutputRegister(), i.MemoryOperand());
break;
case kArm64Str:
__ Str(i.InputRegister(2), i.MemoryOperand());
__ Str(i.InputOrZeroRegister64(2), i.MemoryOperand());
break;
case kArm64LdrS:
__ Ldr(i.OutputDoubleRegister().S(), i.MemoryOperand());
break;
case kArm64StrS:
__ Str(i.InputDoubleRegister(2).S(), i.MemoryOperand());
__ Str(i.InputFloat32OrZeroRegister(2), i.MemoryOperand());
break;
case kArm64LdrD:
__ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
break;
case kArm64StrD:
__ Str(i.InputDoubleRegister(2), i.MemoryOperand());
__ Str(i.InputFloat64OrZeroRegister(2), i.MemoryOperand());
break;
case kCheckedLoadInt8:
ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrsb);
......
......@@ -40,7 +40,9 @@ class Arm64OperandGenerator final : public OperandGenerator {
// Use the zero register if the node has the immediate value zero, otherwise
// assign a register.
InstructionOperand UseRegisterOrImmediateZero(Node* node) {
if (IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) {
if ((IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) ||
(IsFloatConstant(node) &&
(bit_cast<int64_t>(GetFloatConstantValue(node)) == V8_INT64_C(0)))) {
return UseImmediate(node);
}
return UseRegister(node);
......@@ -68,6 +70,19 @@ class Arm64OperandGenerator final : public OperandGenerator {
return OpParameter<int64_t>(node);
}
bool IsFloatConstant(Node* node) {
return (node->opcode() == IrOpcode::kFloat32Constant) ||
(node->opcode() == IrOpcode::kFloat64Constant);
}
double GetFloatConstantValue(Node* node) {
if (node->opcode() == IrOpcode::kFloat32Constant) {
return OpParameter<float>(node);
}
DCHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
return OpParameter<double>(node);
}
bool CanBeImmediate(Node* node, ImmediateMode mode) {
return IsIntegerConstant(node) &&
CanBeImmediate(GetIntegerConstantValue(node), mode);
......@@ -477,10 +492,12 @@ void InstructionSelector::VisitStore(Node* node) {
}
if (g.CanBeImmediate(index, immediate_mode)) {
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
g.UseRegister(base), g.UseImmediate(index),
g.UseRegisterOrImmediateZero(value));
} else {
Emit(opcode | AddressingModeField::encode(kMode_MRR), g.NoOutput(),
g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
g.UseRegister(base), g.UseRegister(index),
g.UseRegisterOrImmediateZero(value));
}
}
}
......@@ -559,7 +576,8 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
return;
}
Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset),
g.UseOperand(length, kArithmeticImm), g.UseRegister(value));
g.UseOperand(length, kArithmeticImm),
g.UseRegisterOrImmediateZero(value));
}
......
......@@ -2250,6 +2250,25 @@ TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
}
}
TEST_P(InstructionSelectorMemoryAccessTest, StoreZero) {
const MemoryAccess memacc = GetParam();
TRACED_FOREACH(int32_t, index, memacc.immediates) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
m.Store(memacc.type.representation(), m.Parameter(0),
m.Int32Constant(index), m.Int32Constant(0), kNoWriteBarrier);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(2)));
EXPECT_EQ(0U, s[0]->OutputCount());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessTest,
......
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