Commit daedefd3 authored by marija.antic's avatar marija.antic Committed by Commit bot

MIPS64: Port "Reland of "MIPS: Optimize load/store with large offset"".

Port 961a45da

BUG=

Review-Url: https://codereview.chromium.org/2505923002
Cr-Commit-Position: refs/heads/master@{#41284}
parent d5ada19c
...@@ -92,9 +92,35 @@ class Mips64OperandGenerator final : public OperandGenerator { ...@@ -92,9 +92,35 @@ class Mips64OperandGenerator final : public OperandGenerator {
case kMips64Tst: case kMips64Tst:
case kMips64Xor: case kMips64Xor:
return is_uint16(value); return is_uint16(value);
case kMips64Lb:
case kMips64Lbu:
case kMips64Sb:
case kMips64Lh:
case kMips64Lhu:
case kMips64Sh:
case kMips64Lw:
case kMips64Sw:
case kMips64Ld:
case kMips64Sd:
case kMips64Lwc1:
case kMips64Swc1:
case kMips64Ldc1: case kMips64Ldc1:
case kMips64Sdc1: case kMips64Sdc1:
return is_int16(value + kIntSize); case kCheckedLoadInt8:
case kCheckedLoadUint8:
case kCheckedLoadInt16:
case kCheckedLoadUint16:
case kCheckedLoadWord32:
case kCheckedLoadWord64:
case kCheckedStoreWord8:
case kCheckedStoreWord16:
case kCheckedStoreWord32:
case kCheckedStoreWord64:
case kCheckedLoadFloat32:
case kCheckedLoadFloat64:
case kCheckedStoreFloat32:
case kCheckedStoreFloat64:
return is_int32(value);
default: default:
return is_int16(value); return is_int16(value);
} }
......
...@@ -1940,19 +1940,42 @@ void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) { ...@@ -1940,19 +1940,42 @@ void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) {
void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) { void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
DCHECK(!src.rm().is(at)); DCHECK(!src.rm().is(at));
DCHECK(is_int32(src.offset_)); DCHECK(is_int32(src.offset_));
daddiu(at, zero_reg, (src.offset_ >> kLuiShift) & kImm16Mask); lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
dsll(at, at, kLuiShift);
ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset. ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
daddu(at, at, src.rm()); // Add base register. daddu(at, at, src.rm()); // Add base register.
} }
// Helper for base-reg + upper part of offset, when offset is larger than int16.
// Loads higher part of the offset to AT register.
// Returns lower part of the offset to be used as offset
// in Load/Store instructions
int32_t Assembler::LoadRegPlusUpperOffsetPartToAt(const MemOperand& src) {
DCHECK(!src.rm().is(at));
DCHECK(is_int32(src.offset_));
int32_t hi = (src.offset_ >> kLuiShift) & kImm16Mask;
// If the highest bit of the lower part of the offset is 1, this would make
// the offset in the load/store instruction negative. We need to compensate
// for this by adding 1 to the upper part of the offset.
if (src.offset_ & kNegOffset) {
if ((hi & kNegOffset) != ((hi + 1) & kNegOffset)) {
LoadRegPlusOffsetToAt(src);
return 0;
}
hi += 1;
}
lui(at, hi);
daddu(at, at, src.rm());
return (src.offset_ & kImm16Mask);
}
void Assembler::lb(Register rd, const MemOperand& rs) { void Assembler::lb(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LB, rs.rm(), rd, rs.offset_); GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0)); GenInstrImmediate(LB, at, rd, off16);
} }
} }
...@@ -1961,8 +1984,8 @@ void Assembler::lbu(Register rd, const MemOperand& rs) { ...@@ -1961,8 +1984,8 @@ void Assembler::lbu(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_); GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0)); GenInstrImmediate(LBU, at, rd, off16);
} }
} }
...@@ -1971,8 +1994,8 @@ void Assembler::lh(Register rd, const MemOperand& rs) { ...@@ -1971,8 +1994,8 @@ void Assembler::lh(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LH, rs.rm(), rd, rs.offset_); GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0)); GenInstrImmediate(LH, at, rd, off16);
} }
} }
...@@ -1981,8 +2004,8 @@ void Assembler::lhu(Register rd, const MemOperand& rs) { ...@@ -1981,8 +2004,8 @@ void Assembler::lhu(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_); GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0)); GenInstrImmediate(LHU, at, rd, off16);
} }
} }
...@@ -1991,8 +2014,8 @@ void Assembler::lw(Register rd, const MemOperand& rs) { ...@@ -1991,8 +2014,8 @@ void Assembler::lw(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LW, rs.rm(), rd, rs.offset_); GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0)); GenInstrImmediate(LW, at, rd, off16);
} }
} }
...@@ -2001,8 +2024,8 @@ void Assembler::lwu(Register rd, const MemOperand& rs) { ...@@ -2001,8 +2024,8 @@ void Assembler::lwu(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_); GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LWU, at, rd, 0); // Equiv to lwu(rd, MemOperand(at, 0)); GenInstrImmediate(LWU, at, rd, off16);
} }
} }
...@@ -2025,8 +2048,8 @@ void Assembler::sb(Register rd, const MemOperand& rs) { ...@@ -2025,8 +2048,8 @@ void Assembler::sb(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(SB, rs.rm(), rd, rs.offset_); GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to store. } else { // Offset > 16 bits, use multiple instructions to store.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0)); GenInstrImmediate(SB, at, rd, off16);
} }
} }
...@@ -2035,8 +2058,8 @@ void Assembler::sh(Register rd, const MemOperand& rs) { ...@@ -2035,8 +2058,8 @@ void Assembler::sh(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(SH, rs.rm(), rd, rs.offset_); GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to store. } else { // Offset > 16 bits, use multiple instructions to store.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0)); GenInstrImmediate(SH, at, rd, off16);
} }
} }
...@@ -2045,8 +2068,8 @@ void Assembler::sw(Register rd, const MemOperand& rs) { ...@@ -2045,8 +2068,8 @@ void Assembler::sw(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(SW, rs.rm(), rd, rs.offset_); GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to store. } else { // Offset > 16 bits, use multiple instructions to store.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0)); GenInstrImmediate(SW, at, rd, off16);
} }
} }
...@@ -2130,8 +2153,8 @@ void Assembler::ld(Register rd, const MemOperand& rs) { ...@@ -2130,8 +2153,8 @@ void Assembler::ld(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(LD, rs.rm(), rd, rs.offset_); GenInstrImmediate(LD, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(LD, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0)); GenInstrImmediate(LD, at, rd, off16);
} }
} }
...@@ -2140,8 +2163,8 @@ void Assembler::sd(Register rd, const MemOperand& rs) { ...@@ -2140,8 +2163,8 @@ void Assembler::sd(Register rd, const MemOperand& rs) {
if (is_int16(rs.offset_)) { if (is_int16(rs.offset_)) {
GenInstrImmediate(SD, rs.rm(), rd, rs.offset_); GenInstrImmediate(SD, rs.rm(), rd, rs.offset_);
} else { // Offset > 16 bits, use multiple instructions to store. } else { // Offset > 16 bits, use multiple instructions to store.
LoadRegPlusOffsetToAt(rs); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
GenInstrImmediate(SD, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0)); GenInstrImmediate(SD, at, rd, off16);
} }
} }
...@@ -2551,8 +2574,8 @@ void Assembler::lwc1(FPURegister fd, const MemOperand& src) { ...@@ -2551,8 +2574,8 @@ void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
if (is_int16(src.offset_)) { if (is_int16(src.offset_)) {
GenInstrImmediate(LWC1, src.rm(), fd, src.offset_); GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(src); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
GenInstrImmediate(LWC1, at, fd, 0); GenInstrImmediate(LWC1, at, fd, off16);
} }
} }
...@@ -2561,8 +2584,8 @@ void Assembler::ldc1(FPURegister fd, const MemOperand& src) { ...@@ -2561,8 +2584,8 @@ void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
if (is_int16(src.offset_)) { if (is_int16(src.offset_)) {
GenInstrImmediate(LDC1, src.rm(), fd, src.offset_); GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(src); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
GenInstrImmediate(LDC1, at, fd, 0); GenInstrImmediate(LDC1, at, fd, off16);
} }
} }
...@@ -2571,8 +2594,8 @@ void Assembler::swc1(FPURegister fd, const MemOperand& src) { ...@@ -2571,8 +2594,8 @@ void Assembler::swc1(FPURegister fd, const MemOperand& src) {
if (is_int16(src.offset_)) { if (is_int16(src.offset_)) {
GenInstrImmediate(SWC1, src.rm(), fd, src.offset_); GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(src); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
GenInstrImmediate(SWC1, at, fd, 0); GenInstrImmediate(SWC1, at, fd, off16);
} }
} }
...@@ -2582,8 +2605,8 @@ void Assembler::sdc1(FPURegister fd, const MemOperand& src) { ...@@ -2582,8 +2605,8 @@ void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
if (is_int16(src.offset_)) { if (is_int16(src.offset_)) {
GenInstrImmediate(SDC1, src.rm(), fd, src.offset_); GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
} else { // Offset > 16 bits, use multiple instructions to load. } else { // Offset > 16 bits, use multiple instructions to load.
LoadRegPlusOffsetToAt(src); int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
GenInstrImmediate(SDC1, at, fd, 0); GenInstrImmediate(SDC1, at, fd, off16);
} }
} }
......
...@@ -1233,6 +1233,7 @@ class Assembler : public AssemblerBase { ...@@ -1233,6 +1233,7 @@ class Assembler : public AssemblerBase {
// Helpers. // Helpers.
void LoadRegPlusOffsetToAt(const MemOperand& src); void LoadRegPlusOffsetToAt(const MemOperand& src);
int32_t LoadRegPlusUpperOffsetPartToAt(const MemOperand& src);
// Relocation for a type-recording IC has the AST id added to it. This // Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to // member variable is a way to pass the information from the call site to
......
...@@ -1360,14 +1360,13 @@ const MemoryAccessImm kMemoryAccessesImm[] = { ...@@ -1360,14 +1360,13 @@ const MemoryAccessImm kMemoryAccessesImm[] = {
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109, -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}}}; 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = { const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
{MachineType::Int8(), {MachineType::Int8(),
kMips64Lb, kMips64Lb,
kMips64Sb, kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger, &InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}}, {-65000, -55000, 32777, 55000, 65000}},
{MachineType::Int8(), {MachineType::Uint8(),
kMips64Lbu, kMips64Lbu,
kMips64Sb, kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger, &InstructionSelectorTest::Stream::IsInteger,
...@@ -1377,7 +1376,7 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = { ...@@ -1377,7 +1376,7 @@ const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
kMips64Sh, kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger, &InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}}, {-65000, -55000, 32777, 55000, 65000}},
{MachineType::Int16(), {MachineType::Uint16(),
kMips64Lhu, kMips64Lhu,
kMips64Sh, kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger, &InstructionSelectorTest::Stream::IsInteger,
...@@ -1601,11 +1600,9 @@ TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest, ...@@ -1601,11 +1600,9 @@ TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
StreamBuilder m(this, memacc.type, MachineType::Pointer()); StreamBuilder m(this, memacc.type, MachineType::Pointer());
m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
Stream s = m.Build(); Stream s = m.Build();
ASSERT_EQ(2U, s.size()); ASSERT_EQ(1U, s.size());
// kMips64Dadd is expected opcode EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
// size more than 16 bits wide EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(1U, s[0]->OutputCount());
} }
...@@ -1621,13 +1618,11 @@ TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest, ...@@ -1621,13 +1618,11 @@ TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier); m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier);
m.Return(m.Int32Constant(0)); m.Return(m.Int32Constant(0));
Stream s = m.Build(); Stream s = m.Build();
ASSERT_EQ(2U, s.size()); ASSERT_EQ(1U, s.size());
// kMips64Add is expected opcode EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
// size more than 16 bits wide EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode()); EXPECT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(kMode_None, s[0]->addressing_mode()); EXPECT_EQ(0U, s[0]->OutputCount());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
} }
} }
......
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