[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}
This commit is contained in:
parent
9622696b5e
commit
0322c20d17
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user