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);
|
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) {
|
DoubleRegister InputOrZeroDoubleRegister(size_t index) {
|
||||||
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
||||||
|
|
||||||
@ -381,45 +389,48 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
|||||||
__ bind(ool->exit()); \
|
__ bind(ool->exit()); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
|
#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
|
||||||
do { \
|
do { \
|
||||||
Label done; \
|
Label done; \
|
||||||
if (instr->InputAt(0)->IsRegister()) { \
|
if (instr->InputAt(0)->IsRegister()) { \
|
||||||
auto offset = i.InputRegister(0); \
|
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)); \
|
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||||
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
||||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||||
} else { \
|
} else { \
|
||||||
auto offset = i.InputOperand(0).immediate(); \
|
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)); \
|
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||||
} \
|
} \
|
||||||
__ bind(&done); \
|
__ bind(&done); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
|
#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
|
||||||
do { \
|
do { \
|
||||||
Label done; \
|
Label done; \
|
||||||
if (instr->InputAt(0)->IsRegister()) { \
|
if (instr->InputAt(0)->IsRegister()) { \
|
||||||
auto offset = i.InputRegister(0); \
|
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)); \
|
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||||
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
__ addu(kScratchReg, i.InputRegister(3), offset); \
|
||||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||||
} else { \
|
} else { \
|
||||||
auto offset = i.InputOperand(0).immediate(); \
|
auto offset = i.InputOperand(0).immediate(); \
|
||||||
auto value = i.InputRegister(2); \
|
auto value = i.InputOrZeroRegister(2); \
|
||||||
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||||
} \
|
} \
|
||||||
__ bind(&done); \
|
__ bind(&done); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
|
#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(mode) \
|
||||||
if (IsMipsArchVariant(kMips32r6)) { \
|
if (IsMipsArchVariant(kMips32r6)) { \
|
||||||
__ cfc1(kScratchReg, FCSR); \
|
__ cfc1(kScratchReg, FCSR); \
|
||||||
@ -478,11 +489,11 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
|||||||
__ sync(); \
|
__ sync(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
||||||
do { \
|
do { \
|
||||||
__ sync(); \
|
__ sync(); \
|
||||||
__ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
|
__ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
|
||||||
__ sync(); \
|
__ sync(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASSEMBLE_IEEE754_BINOP(name) \
|
#define ASSEMBLE_IEEE754_BINOP(name) \
|
||||||
@ -1402,7 +1413,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ lb(i.OutputRegister(), i.MemoryOperand());
|
__ lb(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsSb:
|
case kMipsSb:
|
||||||
__ sb(i.InputRegister(2), i.MemoryOperand());
|
__ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsLhu:
|
case kMipsLhu:
|
||||||
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
||||||
@ -1417,10 +1428,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsSh:
|
case kMipsSh:
|
||||||
__ sh(i.InputRegister(2), i.MemoryOperand());
|
__ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsUsh:
|
case kMipsUsh:
|
||||||
__ Ush(i.InputRegister(2), i.MemoryOperand(), kScratchReg);
|
__ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
|
||||||
break;
|
break;
|
||||||
case kMipsLw:
|
case kMipsLw:
|
||||||
__ lw(i.OutputRegister(), i.MemoryOperand());
|
__ lw(i.OutputRegister(), i.MemoryOperand());
|
||||||
@ -1429,10 +1440,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ Ulw(i.OutputRegister(), i.MemoryOperand());
|
__ Ulw(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsSw:
|
case kMipsSw:
|
||||||
__ sw(i.InputRegister(2), i.MemoryOperand());
|
__ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsUsw:
|
case kMipsUsw:
|
||||||
__ Usw(i.InputRegister(2), i.MemoryOperand());
|
__ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMipsLwc1: {
|
case kMipsLwc1: {
|
||||||
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
||||||
@ -1445,13 +1456,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
case kMipsSwc1: {
|
case kMipsSwc1: {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
MemOperand operand = i.MemoryOperand(&index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case kMipsUswc1: {
|
case kMipsUswc1: {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
MemOperand operand = i.MemoryOperand(&index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case kMipsLdc1:
|
case kMipsLdc1:
|
||||||
@ -1460,12 +1479,22 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
case kMipsUldc1:
|
case kMipsUldc1:
|
||||||
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
||||||
break;
|
break;
|
||||||
case kMipsSdc1:
|
case kMipsSdc1: {
|
||||||
__ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
|
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||||
|
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||||
|
__ Move(kDoubleRegZero, 0.0);
|
||||||
|
}
|
||||||
|
__ sdc1(ft, i.MemoryOperand());
|
||||||
break;
|
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;
|
break;
|
||||||
|
}
|
||||||
case kMipsPush:
|
case kMipsPush:
|
||||||
if (instr->InputAt(0)->IsFPRegister()) {
|
if (instr->InputAt(0)->IsFPRegister()) {
|
||||||
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
||||||
|
@ -31,6 +31,39 @@ class MipsOperandGenerator final : public OperandGenerator {
|
|||||||
return UseRegister(node);
|
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) {
|
bool CanBeImmediate(Node* node, InstructionCode opcode) {
|
||||||
Int32Matcher m(node);
|
Int32Matcher m(node);
|
||||||
if (!m.HasValue()) return false;
|
if (!m.HasValue()) return false;
|
||||||
@ -301,14 +334,15 @@ void InstructionSelector::VisitStore(Node* node) {
|
|||||||
|
|
||||||
if (g.CanBeImmediate(index, opcode)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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);
|
: g.UseRegister(length);
|
||||||
|
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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));
|
g.UseRegister(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1803,14 +1838,15 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
|
|||||||
|
|
||||||
if (g.CanBeImmediate(index, opcode)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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);
|
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) {
|
DoubleRegister InputOrZeroDoubleRegister(size_t index) {
|
||||||
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
|
||||||
|
|
||||||
@ -400,14 +408,20 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
|||||||
Label done; \
|
Label done; \
|
||||||
if (instr->InputAt(0)->IsRegister()) { \
|
if (instr->InputAt(0)->IsRegister()) { \
|
||||||
auto offset = i.InputRegister(0); \
|
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)); \
|
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||||
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
||||||
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
||||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||||
} else { \
|
} else { \
|
||||||
int offset = static_cast<int>(i.InputOperand(0).immediate()); \
|
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)); \
|
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||||
} \
|
} \
|
||||||
@ -419,14 +433,14 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
|||||||
Label done; \
|
Label done; \
|
||||||
if (instr->InputAt(0)->IsRegister()) { \
|
if (instr->InputAt(0)->IsRegister()) { \
|
||||||
auto offset = i.InputRegister(0); \
|
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)); \
|
__ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
|
||||||
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
__ And(kScratchReg, offset, Operand(0xffffffff)); \
|
||||||
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
__ Daddu(kScratchReg, i.InputRegister(3), kScratchReg); \
|
||||||
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
__ asm_instr(value, MemOperand(kScratchReg, 0)); \
|
||||||
} else { \
|
} else { \
|
||||||
int offset = static_cast<int>(i.InputOperand(0).immediate()); \
|
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)); \
|
__ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \
|
||||||
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
__ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \
|
||||||
} \
|
} \
|
||||||
@ -489,11 +503,11 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
|||||||
__ sync(); \
|
__ sync(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
|
||||||
do { \
|
do { \
|
||||||
__ sync(); \
|
__ sync(); \
|
||||||
__ asm_instr(i.InputRegister(2), i.MemoryOperand()); \
|
__ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
|
||||||
__ sync(); \
|
__ sync(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASSEMBLE_IEEE754_BINOP(name) \
|
#define ASSEMBLE_IEEE754_BINOP(name) \
|
||||||
@ -1683,7 +1697,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ lb(i.OutputRegister(), i.MemoryOperand());
|
__ lb(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Sb:
|
case kMips64Sb:
|
||||||
__ sb(i.InputRegister(2), i.MemoryOperand());
|
__ sb(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Lhu:
|
case kMips64Lhu:
|
||||||
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
__ lhu(i.OutputRegister(), i.MemoryOperand());
|
||||||
@ -1698,10 +1712,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
__ Ulh(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Sh:
|
case kMips64Sh:
|
||||||
__ sh(i.InputRegister(2), i.MemoryOperand());
|
__ sh(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Ush:
|
case kMips64Ush:
|
||||||
__ Ush(i.InputRegister(2), i.MemoryOperand(), kScratchReg);
|
__ Ush(i.InputOrZeroRegister(2), i.MemoryOperand(), kScratchReg);
|
||||||
break;
|
break;
|
||||||
case kMips64Lw:
|
case kMips64Lw:
|
||||||
__ lw(i.OutputRegister(), i.MemoryOperand());
|
__ lw(i.OutputRegister(), i.MemoryOperand());
|
||||||
@ -1722,16 +1736,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
__ Uld(i.OutputRegister(), i.MemoryOperand());
|
__ Uld(i.OutputRegister(), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Sw:
|
case kMips64Sw:
|
||||||
__ sw(i.InputRegister(2), i.MemoryOperand());
|
__ sw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Usw:
|
case kMips64Usw:
|
||||||
__ Usw(i.InputRegister(2), i.MemoryOperand());
|
__ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Sd:
|
case kMips64Sd:
|
||||||
__ sd(i.InputRegister(2), i.MemoryOperand());
|
__ sd(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Usd:
|
case kMips64Usd:
|
||||||
__ Usd(i.InputRegister(2), i.MemoryOperand());
|
__ Usd(i.InputOrZeroRegister(2), i.MemoryOperand());
|
||||||
break;
|
break;
|
||||||
case kMips64Lwc1: {
|
case kMips64Lwc1: {
|
||||||
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
__ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
|
||||||
@ -1744,13 +1758,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
case kMips64Swc1: {
|
case kMips64Swc1: {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
MemOperand operand = i.MemoryOperand(&index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case kMips64Uswc1: {
|
case kMips64Uswc1: {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
MemOperand operand = i.MemoryOperand(&index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case kMips64Ldc1:
|
case kMips64Ldc1:
|
||||||
@ -1759,12 +1781,22 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
|||||||
case kMips64Uldc1:
|
case kMips64Uldc1:
|
||||||
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
__ Uldc1(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg);
|
||||||
break;
|
break;
|
||||||
case kMips64Sdc1:
|
case kMips64Sdc1: {
|
||||||
__ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
|
FPURegister ft = i.InputOrZeroDoubleRegister(2);
|
||||||
|
if (ft.is(kDoubleRegZero) && !__ IsDoubleZeroRegSet()) {
|
||||||
|
__ Move(kDoubleRegZero, 0.0);
|
||||||
|
}
|
||||||
|
__ sdc1(ft, i.MemoryOperand());
|
||||||
break;
|
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;
|
break;
|
||||||
|
}
|
||||||
case kMips64Push:
|
case kMips64Push:
|
||||||
if (instr->InputAt(0)->IsFPRegister()) {
|
if (instr->InputAt(0)->IsFPRegister()) {
|
||||||
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
__ sdc1(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
|
||||||
|
@ -31,6 +31,17 @@ class Mips64OperandGenerator final : public OperandGenerator {
|
|||||||
return UseRegister(node);
|
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) {
|
bool IsIntegerConstant(Node* node) {
|
||||||
return (node->opcode() == IrOpcode::kInt32Constant) ||
|
return (node->opcode() == IrOpcode::kInt32Constant) ||
|
||||||
(node->opcode() == IrOpcode::kInt64Constant);
|
(node->opcode() == IrOpcode::kInt64Constant);
|
||||||
@ -44,6 +55,19 @@ class Mips64OperandGenerator final : public OperandGenerator {
|
|||||||
return OpParameter<int64_t>(node);
|
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) {
|
bool CanBeImmediate(Node* node, InstructionCode mode) {
|
||||||
return IsIntegerConstant(node) &&
|
return IsIntegerConstant(node) &&
|
||||||
CanBeImmediate(GetIntegerConstantValue(node), mode);
|
CanBeImmediate(GetIntegerConstantValue(node), mode);
|
||||||
@ -401,14 +425,15 @@ void InstructionSelector::VisitStore(Node* node) {
|
|||||||
|
|
||||||
if (g.CanBeImmediate(index, opcode)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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);
|
: g.UseRegister(length);
|
||||||
|
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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));
|
g.UseRegister(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2519,14 +2545,15 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
|
|||||||
|
|
||||||
if (g.CanBeImmediate(index, opcode)) {
|
if (g.CanBeImmediate(index, opcode)) {
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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 {
|
} else {
|
||||||
InstructionOperand addr_reg = g.TempRegister();
|
InstructionOperand addr_reg = g.TempRegister();
|
||||||
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
|
||||||
g.UseRegister(index), g.UseRegister(base));
|
g.UseRegister(index), g.UseRegister(base));
|
||||||
// Emit desired store opcode, using temp addr_reg.
|
// Emit desired store opcode, using temp addr_reg.
|
||||||
Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
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()),
|
test->isolate(), new (test->zone()) Graph(test->zone()),
|
||||||
MakeCallDescriptor(test->zone(), return_type, parameter0_type),
|
MakeCallDescriptor(test->zone(), return_type, parameter0_type),
|
||||||
MachineType::PointerRepresentation(),
|
MachineType::PointerRepresentation(),
|
||||||
MachineOperatorBuilder::kAllOptionalOps),
|
MachineOperatorBuilder::kAllOptionalOps,
|
||||||
|
InstructionSelector::AlignmentRequirements()),
|
||||||
test_(test) {}
|
test_(test) {}
|
||||||
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
|
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
|
||||||
MachineType parameter0_type, MachineType parameter1_type)
|
MachineType parameter0_type, MachineType parameter1_type)
|
||||||
|
@ -859,6 +859,18 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
|
|||||||
return os << acc.type;
|
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.
|
// Loads and stores immediate values.
|
||||||
@ -954,6 +966,40 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
|
|||||||
&InstructionSelectorTest::Stream::IsDouble,
|
&InstructionSelectorTest::Stream::IsDouble,
|
||||||
{-65000, -55000, 32777, 55000, 65000}}};
|
{-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
|
} // 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,
|
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
|
||||||
InstructionSelectorMemoryAccessImmTest,
|
InstructionSelectorMemoryAccessImmTest,
|
||||||
::testing::ValuesIn(kMemoryAccessesImm));
|
::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.
|
// Load/store offsets more than 16 bits.
|
||||||
|
@ -1284,6 +1284,18 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
|
|||||||
return os << acc.type;
|
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
|
// Loads and stores immediate values
|
||||||
@ -1391,6 +1403,48 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
|
|||||||
&InstructionSelectorTest::Stream::IsInteger,
|
&InstructionSelectorTest::Stream::IsInteger,
|
||||||
{-65000, -55000, 32777, 55000, 65000}}};
|
{-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
|
} // 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,
|
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
|
||||||
InstructionSelectorMemoryAccessImmTest,
|
InstructionSelectorMemoryAccessImmTest,
|
||||||
::testing::ValuesIn(kMemoryAccessesImm));
|
::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.
|
// Load/store offsets more than 16 bits.
|
||||||
|
Loading…
Reference in New Issue
Block a user