MIPS[64]: Port '[turbofan] Use zr to store immediate zero'
Port 0322c20d17
Original commit message:
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/2470133005
Cr-Commit-Position: refs/heads/master@{#40987}
This commit is contained in:
parent
815eca573a
commit
b725d5a797
@ -54,6 +54,14 @@ class MipsOperandConverter final : public InstructionOperandConverter {
|
||||
return ToDoubleRegister(op);
|
||||
}
|
||||
|
||||
Register InputOrZeroRegister(size_t index) {
|
||||
if (instr_->InputAt(index)->IsImmediate()) {
|
||||
DCHECK((InputInt32(index) == 0));
|
||||
return zero_reg;
|
||||
}
|
||||
return InputRegister(index);
|
||||
}
|
||||
|
||||
DoubleRegister InputOrZeroDoubleRegister(size_t index) {
|
||||
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
||||
|
||||
@ -381,45 +389,48 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
__ bind(ool->exit()); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
|
||||
do { \
|
||||
Label done; \
|
||||
if (instr->InputAt(0)->IsRegister()) { \
|
||||
auto offset = i.InputRegister(0); \
|
||||
auto value = i.Input##width##Register(2); \
|
||||
auto value = i.InputOrZero##width##Register(2); \
|
||||
if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \
|
||||
__ Move(kDoubleRegZero, 0.0); \
|
||||
} \
|
||||
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||
} else { \
|
||||
auto offset = i.InputOperand(0).immediate(); \
|
||||
auto value = i.Input##width##Register(2); \
|
||||
auto value = i.InputOrZero##width##Register(2); \
|
||||
if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \
|
||||
__ Move(kDoubleRegZero, 0.0); \
|
||||
} \
|
||||
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
|
||||
do { \
|
||||
Label done; \
|
||||
if (instr->InputAt(0)->IsRegister()) { \
|
||||
auto offset = i.InputRegister(0); \
|
||||
auto value = i.InputRegister(2); \
|
||||
auto value = i.InputOrZeroRegister(2); \
|
||||
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||
} else { \
|
||||
auto offset = i.InputOperand(0).immediate(); \
|
||||
auto value = i.InputRegister(2); \
|
||||
auto value = i.InputOrZeroRegister(2); \
|
||||
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
|
||||
if (IsMipsArchVariant(kMips32r6)) { \
|
||||
__ cfc1(kScratchReg, FCSR); \
|
||||
@ -481,7 +492,7 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
||||
do { \
|
||||
__ sync(); \
|
||||
__ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
|
||||
__ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
@ -1402,7 +1413,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ lb(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsSb:
|
||||
__ sb(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsLhu:
|
||||
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
||||
@ -1417,10 +1428,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsSh:
|
||||
__ sh(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsUsh:
|
||||
__ Ush(i.InputRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
__ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
case kMipsLw:
|
||||
__ lw(i.OutputRegister(), i.MemoryOperand());
|
||||
@ -1429,10 +1440,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Ulw(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsSw:
|
||||
__ sw(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsUsw:
|
||||
__ Usw(i.InputRegister(2), i.MemoryOperand());
|
||||
__ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMipsLwc1: {
|
||||
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
||||
@ -1445,13 +1456,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kMipsSwc1: {
|
||||
size_t index = 0;
|
||||
MemOperand operand = i.MemoryOperand(&index);
|
||||
__ swc1(i.InputSingleRegister(index), operand);
|
||||
FPURegister ft = i.InputOrZeroSingleRegister(index);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ swc1(ft, operand);
|
||||
break;
|
||||
}
|
||||
case kMipsUswc1: {
|
||||
size_t index = 0;
|
||||
MemOperand operand = i.MemoryOperand(&index);
|
||||
__ Uswc1(i.InputSingleRegister(index), operand, kScratchReg);
|
||||
FPURegister ft = i.InputOrZeroSingleRegister(index);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ Uswc1(ft, operand, kScratchReg);
|
||||
break;
|
||||
}
|
||||
case kMipsLdc1:
|
||||
@ -1460,12 +1479,22 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kMipsUldc1:
|
||||
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
case kMipsSdc1:
|
||||
__ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
|
||||
case kMipsSdc1: {
|
||||
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ sdc1(ft, i.MemoryOperand());
|
||||
break;
|
||||
case kMipsUsdc1:
|
||||
__ Usdc1(i.InputDoubleRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
}
|
||||
case kMipsUsdc1: {
|
||||
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ Usdc1(ft, i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
}
|
||||
case kMipsPush:
|
||||
if (instr->InputAt(0)->IsFPRegister()) {
|
||||
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
||||
|
@ -31,6 +31,39 @@ class MipsOperandGenerator final : public OperandGenerator {
|
||||
return UseRegister(node);
|
||||
}
|
||||
|
||||
// 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)) ||
|
||||
(IsFloatConstant(node) &&
|
||||
(bit_cast<int64_t>(GetFloatConstantValue(node)) == V8_INT64_C(0)))) {
|
||||
return UseImmediate(node);
|
||||
}
|
||||
return UseRegister(node);
|
||||
}
|
||||
|
||||
bool IsIntegerConstant(Node* node) {
|
||||
return (node->opcode() == IrOpcode::kInt32Constant);
|
||||
}
|
||||
|
||||
int64_t GetIntegerConstantValue(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kInt32Constant);
|
||||
return OpParameter<int32_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, InstructionCode opcode) {
|
||||
Int32Matcher m(node);
|
||||
if (!m.HasValue()) return false;
|
||||
@ -301,14 +334,15 @@ void InstructionSelector::VisitStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1233,14 +1267,15 @@ void InstructionSelector::VisitUnalignedStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1332,7 +1367,7 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
|
||||
: g.UseRegister(length);
|
||||
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
offset_operand, length_operand, g.UseRegister(value),
|
||||
offset_operand, length_operand, g.UseRegisterOrImmediateZero(value),
|
||||
g.UseRegister(buffer));
|
||||
}
|
||||
|
||||
@ -1803,14 +1838,15 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,14 @@ class MipsOperandConverter final : public InstructionOperandConverter {
|
||||
return ToDoubleRegister(op);
|
||||
}
|
||||
|
||||
Register InputOrZeroRegister(size_t index) {
|
||||
if (instr_->InputAt(index)->IsImmediate()) {
|
||||
DCHECK((InputInt32(index) == 0));
|
||||
return zero_reg;
|
||||
}
|
||||
return InputRegister(index);
|
||||
}
|
||||
|
||||
DoubleRegister InputOrZeroDoubleRegister(size_t index) {
|
||||
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
||||
|
||||
@ -400,14 +408,20 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
Label done; \
|
||||
if (instr->InputAt(0)->IsRegister()) { \
|
||||
auto offset = i.InputRegister(0); \
|
||||
auto value = i.Input##width##Register(2); \
|
||||
auto value = i.InputOrZero##width##Register(2); \
|
||||
if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \
|
||||
__ Move(kDoubleRegZero, 0.0); \
|
||||
} \
|
||||
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
||||
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||
} else { \
|
||||
int offset = static_cast<int>(i.InputOperand(0).immediate()); \
|
||||
auto value = i.Input##width##Register(2); \
|
||||
auto value = i.InputOrZero##width##Register(2); \
|
||||
if (value.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) { \
|
||||
__ Move(kDoubleRegZero, 0.0); \
|
||||
} \
|
||||
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||
} \
|
||||
@ -419,14 +433,14 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
Label done; \
|
||||
if (instr->InputAt(0)->IsRegister()) { \
|
||||
auto offset = i.InputRegister(0); \
|
||||
auto value = i.InputRegister(2); \
|
||||
auto value = i.InputOrZeroRegister(2); \
|
||||
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
||||
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||
} else { \
|
||||
int offset = static_cast<int>(i.InputOperand(0).immediate()); \
|
||||
auto value = i.InputRegister(2); \
|
||||
auto value = i.InputOrZeroRegister(2); \
|
||||
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||
} \
|
||||
@ -492,7 +506,7 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
||||
do { \
|
||||
__ sync(); \
|
||||
__ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
|
||||
__ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
@ -1683,7 +1697,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ lb(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Sb:
|
||||
__ sb(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Lhu:
|
||||
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
||||
@ -1698,10 +1712,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Sh:
|
||||
__ sh(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Ush:
|
||||
__ Ush(i.InputRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
__ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
case kMips64Lw:
|
||||
__ lw(i.OutputRegister(), i.MemoryOperand());
|
||||
@ -1722,16 +1736,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Uld(i.OutputRegister(), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Sw:
|
||||
__ sw(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Usw:
|
||||
__ Usw(i.InputRegister(2), i.MemoryOperand());
|
||||
__ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Sd:
|
||||
__ sd(i.InputRegister(2), i.MemoryOperand());
|
||||
__ sd(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Usd:
|
||||
__ Usd(i.InputRegister(2), i.MemoryOperand());
|
||||
__ Usd(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Lwc1: {
|
||||
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
||||
@ -1744,13 +1758,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kMips64Swc1: {
|
||||
size_t index = 0;
|
||||
MemOperand operand = i.MemoryOperand(&index);
|
||||
__ swc1(i.InputSingleRegister(index), operand);
|
||||
FPURegister ft = i.InputOrZeroSingleRegister(index);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ swc1(ft, operand);
|
||||
break;
|
||||
}
|
||||
case kMips64Uswc1: {
|
||||
size_t index = 0;
|
||||
MemOperand operand = i.MemoryOperand(&index);
|
||||
__ Uswc1(i.InputSingleRegister(index), operand, kScratchReg);
|
||||
FPURegister ft = i.InputOrZeroSingleRegister(index);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ Uswc1(ft, operand, kScratchReg);
|
||||
break;
|
||||
}
|
||||
case kMips64Ldc1:
|
||||
@ -1759,12 +1781,22 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kMips64Uldc1:
|
||||
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
case kMips64Sdc1:
|
||||
__ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
|
||||
case kMips64Sdc1: {
|
||||
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ sdc1(ft, i.MemoryOperand());
|
||||
break;
|
||||
case kMips64Usdc1:
|
||||
__ Usdc1(i.InputDoubleRegister(2), i.MemoryOperand(), kScratchReg);
|
||||
}
|
||||
case kMips64Usdc1: {
|
||||
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||
__ Move(kDoubleRegZero, 0.0);
|
||||
}
|
||||
__ Usdc1(ft, i.MemoryOperand(), kScratchReg);
|
||||
break;
|
||||
}
|
||||
case kMips64Push:
|
||||
if (instr->InputAt(0)->IsFPRegister()) {
|
||||
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
||||
|
@ -31,6 +31,17 @@ class Mips64OperandGenerator final : public OperandGenerator {
|
||||
return UseRegister(node);
|
||||
}
|
||||
|
||||
// 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)) ||
|
||||
(IsFloatConstant(node) &&
|
||||
(bit_cast<int64_t>(GetFloatConstantValue(node)) == V8_INT64_C(0)))) {
|
||||
return UseImmediate(node);
|
||||
}
|
||||
return UseRegister(node);
|
||||
}
|
||||
|
||||
bool IsIntegerConstant(Node* node) {
|
||||
return (node->opcode() == IrOpcode::kInt32Constant) ||
|
||||
(node->opcode() == IrOpcode::kInt64Constant);
|
||||
@ -44,6 +55,19 @@ class Mips64OperandGenerator 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, InstructionCode mode) {
|
||||
return IsIntegerConstant(node) &&
|
||||
CanBeImmediate(GetIntegerConstantValue(node), mode);
|
||||
@ -401,14 +425,15 @@ void InstructionSelector::VisitStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1767,14 +1792,15 @@ void InstructionSelector::VisitUnalignedStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1876,7 +1902,7 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
|
||||
: g.UseRegister(length);
|
||||
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
offset_operand, length_operand, g.UseRegister(value),
|
||||
offset_operand, length_operand, g.UseRegisterOrImmediateZero(value),
|
||||
g.UseRegister(buffer));
|
||||
}
|
||||
|
||||
@ -2519,14 +2545,15 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
|
||||
|
||||
if (g.CanBeImmediate(index, opcode)) {
|
||||
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 {
|
||||
InstructionOperand addr_reg = g.TempRegister();
|
||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||
g.UseRegister(index), g.UseRegister(base));
|
||||
// Emit desired store opcode, using temp addr_reg.
|
||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
||||
addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
||||
addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,8 @@ class InstructionSelectorTest : public TestWithContext,
|
||||
test->isolate(), new (test->zone()) Graph(test->zone()),
|
||||
MakeCallDescriptor(test->zone(), return_type, parameter0_type),
|
||||
MachineType::PointerRepresentation(),
|
||||
MachineOperatorBuilder::kAllOptionalOps),
|
||||
MachineOperatorBuilder::kAllOptionalOps,
|
||||
InstructionSelector::AlignmentRequirements()),
|
||||
test_(test) {}
|
||||
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
|
||||
MachineType parameter0_type, MachineType parameter1_type)
|
||||
|
@ -859,6 +859,18 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
|
||||
return os << acc.type;
|
||||
}
|
||||
|
||||
struct MemoryAccessImm2 {
|
||||
MachineType type;
|
||||
ArchOpcode store_opcode;
|
||||
ArchOpcode store_opcode_unaligned;
|
||||
bool (InstructionSelectorTest::Stream::*val_predicate)(
|
||||
const InstructionOperand*) const;
|
||||
const int32_t immediates[40];
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm2& acc) {
|
||||
return os << acc.type;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Loads and stores immediate values.
|
||||
@ -954,6 +966,40 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
|
||||
&InstructionSelectorTest::Stream::IsDouble,
|
||||
{-65000, -55000, 32777, 55000, 65000}}};
|
||||
|
||||
const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = {
|
||||
{MachineType::Int16(),
|
||||
kMipsUsh,
|
||||
kMipsSh,
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Int32(),
|
||||
kMipsUsw,
|
||||
kMipsSw,
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Float32(),
|
||||
kMipsUswc1,
|
||||
kMipsSwc1,
|
||||
&InstructionSelectorTest::Stream::IsDouble,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Float64(),
|
||||
kMipsUsdc1,
|
||||
kMipsSdc1,
|
||||
&InstructionSelectorTest::Stream::IsDouble,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -1043,11 +1089,60 @@ TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(InstructionSelectorMemoryAccessImmTest, StoreZero) {
|
||||
const MemoryAccessImm 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.store_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,
|
||||
InstructionSelectorMemoryAccessImmTest,
|
||||
::testing::ValuesIn(kMemoryAccessesImm));
|
||||
|
||||
typedef InstructionSelectorTestWithParam<MemoryAccessImm2>
|
||||
InstructionSelectorMemoryAccessUnalignedImmTest;
|
||||
|
||||
TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest, StoreZero) {
|
||||
const MemoryAccessImm2 memacc = GetParam();
|
||||
TRACED_FOREACH(int32_t, index, memacc.immediates) {
|
||||
StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
|
||||
bool unaligned_store_supported = m.machine()->UnalignedStoreSupported(
|
||||
MachineType::TypeForRepresentation(memacc.type.representation()), 1);
|
||||
m.UnalignedStore(memacc.type.representation(), m.Parameter(0),
|
||||
m.Int32Constant(index), m.Int32Constant(0));
|
||||
m.Return(m.Int32Constant(0));
|
||||
Stream s = m.Build();
|
||||
ASSERT_EQ(1U, s.size());
|
||||
EXPECT_EQ(unaligned_store_supported ? memacc.store_opcode_unaligned
|
||||
: memacc.store_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,
|
||||
InstructionSelectorMemoryAccessUnalignedImmTest,
|
||||
::testing::ValuesIn(kMemoryAccessesImmUnaligned));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Load/store offsets more than 16 bits.
|
||||
|
@ -1284,6 +1284,18 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
|
||||
return os << acc.type;
|
||||
}
|
||||
|
||||
struct MemoryAccessImm2 {
|
||||
MachineType type;
|
||||
ArchOpcode store_opcode;
|
||||
ArchOpcode store_opcode_unaligned;
|
||||
bool (InstructionSelectorTest::Stream::*val_predicate)(
|
||||
const InstructionOperand*) const;
|
||||
const int32_t immediates[40];
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm2& acc) {
|
||||
return os << acc.type;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Loads and stores immediate values
|
||||
@ -1391,6 +1403,48 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-65000, -55000, 32777, 55000, 65000}}};
|
||||
|
||||
const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = {
|
||||
{MachineType::Int16(),
|
||||
kMips64Ush,
|
||||
kMips64Sh,
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Int32(),
|
||||
kMips64Usw,
|
||||
kMips64Sw,
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Int64(),
|
||||
kMips64Usd,
|
||||
kMips64Sd,
|
||||
&InstructionSelectorTest::Stream::IsInteger,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Float32(),
|
||||
kMips64Uswc1,
|
||||
kMips64Swc1,
|
||||
&InstructionSelectorTest::Stream::IsDouble,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
|
||||
{MachineType::Float64(),
|
||||
kMips64Usdc1,
|
||||
kMips64Sdc1,
|
||||
&InstructionSelectorTest::Stream::IsDouble,
|
||||
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
|
||||
-89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
|
||||
39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
|
||||
286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -1477,10 +1531,60 @@ TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(InstructionSelectorMemoryAccessImmTest, StoreZero) {
|
||||
const MemoryAccessImm 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.store_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,
|
||||
InstructionSelectorMemoryAccessImmTest,
|
||||
::testing::ValuesIn(kMemoryAccessesImm));
|
||||
|
||||
typedef InstructionSelectorTestWithParam<MemoryAccessImm2>
|
||||
InstructionSelectorMemoryAccessUnalignedImmTest;
|
||||
|
||||
TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest, StoreZero) {
|
||||
const MemoryAccessImm2 memacc = GetParam();
|
||||
TRACED_FOREACH(int32_t, index, memacc.immediates) {
|
||||
StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
|
||||
bool unaligned_store_supported = m.machine()->UnalignedStoreSupported(
|
||||
MachineType::TypeForRepresentation(memacc.type.representation()), 1);
|
||||
m.UnalignedStore(memacc.type.representation(), m.Parameter(0),
|
||||
m.Int32Constant(index), m.Int32Constant(0));
|
||||
m.Return(m.Int32Constant(0));
|
||||
Stream s = m.Build();
|
||||
ASSERT_EQ(1U, s.size());
|
||||
EXPECT_EQ(unaligned_store_supported ? memacc.store_opcode_unaligned
|
||||
: memacc.store_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,
|
||||
InstructionSelectorMemoryAccessUnalignedImmTest,
|
||||
::testing::ValuesIn(kMemoryAccessesImmUnaligned));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Load/store offsets more than 16 bits.
|
||||
|
Loading…
Reference in New Issue
Block a user