From bca9d01dc54f606f803107dc6ca4d047e77fe61b Mon Sep 17 00:00:00 2001 From: "baptiste.afsa@arm.com" Date: Fri, 12 Sep 2014 09:31:26 +0000 Subject: [PATCH] [turbofan] Tests and fixes for ARM64 load/store with immediate offset. R=bmeurer@chromium.org, ulan@chromium.org BUG= Review URL: https://codereview.chromium.org/550113002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23906 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm64/assembler-arm64.h | 5 +- .../arm64/instruction-selector-arm64-unittest.cc | 77 +++++++++++++++++++--- src/compiler/arm64/instruction-selector-arm64.cc | 40 +++++++++-- 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h index a06c969..82b4500 100644 --- a/src/arm64/assembler-arm64.h +++ b/src/arm64/assembler-arm64.h @@ -1850,6 +1850,9 @@ class Assembler : public AssemblerBase { inline static Instr ImmBarrierType(int imm2); inline static LSDataSize CalcLSDataSize(LoadStoreOp op); + static bool IsImmLSUnscaled(int64_t offset); + static bool IsImmLSScaled(int64_t offset, LSDataSize size); + // Move immediates encoding. inline static Instr ImmMoveWide(uint64_t imm); inline static Instr ShiftMoveWide(int64_t shift); @@ -1933,8 +1936,6 @@ class Assembler : public AssemblerBase { void LoadStore(const CPURegister& rt, const MemOperand& addr, LoadStoreOp op); - static bool IsImmLSUnscaled(int64_t offset); - static bool IsImmLSScaled(int64_t offset, LSDataSize size); void LoadStorePair(const CPURegister& rt, const CPURegister& rt2, const MemOperand& addr, LoadStorePairOp op); diff --git a/src/compiler/arm64/instruction-selector-arm64-unittest.cc b/src/compiler/arm64/instruction-selector-arm64-unittest.cc index b2abe6e..21b130b 100644 --- a/src/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/src/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -855,6 +855,7 @@ struct MemoryAccess { MachineType type; ArchOpcode ldr_opcode; ArchOpcode str_opcode; + const int32_t immediates[20]; }; @@ -868,16 +869,36 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { static const MemoryAccess kMemoryAccesses[] = { - {kMachInt8, kArm64Ldrsb, kArm64Strb}, - {kMachUint8, kArm64Ldrb, kArm64Strb}, - {kMachInt16, kArm64Ldrsh, kArm64Strh}, - {kMachUint16, kArm64Ldrh, kArm64Strh}, - {kMachInt32, kArm64LdrW, kArm64StrW}, - {kMachUint32, kArm64LdrW, kArm64StrW}, - {kMachInt64, kArm64Ldr, kArm64Str}, - {kMachUint64, kArm64Ldr, kArm64Str}, - {kMachFloat32, kArm64LdrS, kArm64StrS}, - {kMachFloat64, kArm64LdrD, kArm64StrD}}; + {kMachInt8, kArm64Ldrsb, kArm64Strb, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, + 2121, 2442, 4093, 4094, 4095}}, + {kMachUint8, kArm64Ldrb, kArm64Strb, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, + 2121, 2442, 4093, 4094, 4095}}, + {kMachInt16, kArm64Ldrsh, kArm64Strh, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, + 4100, 4242, 6786, 8188, 8190}}, + {kMachUint16, kArm64Ldrh, kArm64Strh, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, + 4100, 4242, 6786, 8188, 8190}}, + {kMachInt32, kArm64LdrW, kArm64StrW, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, + 8196, 3276, 3280, 16376, 16380}}, + {kMachUint32, kArm64LdrW, kArm64StrW, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, + 8196, 3276, 3280, 16376, 16380}}, + {kMachInt64, kArm64Ldr, kArm64Str, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, + 8200, 16384, 16392, 32752, 32760}}, + {kMachUint64, kArm64Ldr, kArm64Str, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, + 8200, 16384, 16392, 32752, 32760}}, + {kMachFloat32, kArm64LdrS, kArm64StrS, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, + 8196, 3276, 3280, 16376, 16380}}, + {kMachFloat64, kArm64LdrD, kArm64StrD, + {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, + 8200, 16384, 16392, 32752, 32760}}}; typedef InstructionSelectorTestWithParam @@ -897,6 +918,23 @@ TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { } +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, memacc.type, kMachPtr); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { const MemoryAccess memacc = GetParam(); StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); @@ -911,6 +949,25 @@ TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { } +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index), + m.Parameter(1)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + + INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMemoryAccessTest, ::testing::ValuesIn(kMemoryAccesses)); diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index fa2f17f..7c88ee9 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -15,7 +15,10 @@ enum ImmediateMode { kShift64Imm, // 0 - 63 kLogical32Imm, kLogical64Imm, - kLoadStoreImm, // unsigned 9 bit or signed 7 bit + kLoadStoreImm8, // signed 8 bit or 12 bit unsigned scaled by access size + kLoadStoreImm16, + kLoadStoreImm32, + kLoadStoreImm64, kNoImmediate }; @@ -54,14 +57,25 @@ class Arm64OperandGenerator FINAL : public OperandGenerator { return 0 <= value && value < 32; case kShift64Imm: return 0 <= value && value < 64; - case kLoadStoreImm: - return (0 <= value && value < (1 << 9)) || - (-(1 << 6) <= value && value < (1 << 6)); + case kLoadStoreImm8: + return IsLoadStoreImmediate(value, LSByte); + case kLoadStoreImm16: + return IsLoadStoreImmediate(value, LSHalfword); + case kLoadStoreImm32: + return IsLoadStoreImmediate(value, LSWord); + case kLoadStoreImm64: + return IsLoadStoreImmediate(value, LSDoubleWord); case kNoImmediate: return false; } return false; } + + private: + bool IsLoadStoreImmediate(int64_t value, LSDataSize size) { + return Assembler::IsImmLSScaled(value, size) || + Assembler::IsImmLSUnscaled(value); + } }; @@ -142,32 +156,39 @@ void InstructionSelector::VisitLoad(Node* node) { Node* base = node->InputAt(0); Node* index = node->InputAt(1); ArchOpcode opcode; + ImmediateMode immediate_mode = kNoImmediate; switch (rep) { case kRepFloat32: opcode = kArm64LdrS; + immediate_mode = kLoadStoreImm32; break; case kRepFloat64: opcode = kArm64LdrD; + immediate_mode = kLoadStoreImm64; break; case kRepBit: // Fall through. case kRepWord8: opcode = typ == kTypeInt32 ? kArm64Ldrsb : kArm64Ldrb; + immediate_mode = kLoadStoreImm8; break; case kRepWord16: opcode = typ == kTypeInt32 ? kArm64Ldrsh : kArm64Ldrh; + immediate_mode = kLoadStoreImm16; break; case kRepWord32: opcode = kArm64LdrW; + immediate_mode = kLoadStoreImm32; break; case kRepTagged: // Fall through. case kRepWord64: opcode = kArm64Ldr; + immediate_mode = kLoadStoreImm64; break; default: UNREACHABLE(); return; } - if (g.CanBeImmediate(index, kLoadStoreImm)) { + if (g.CanBeImmediate(index, immediate_mode)) { Emit(opcode | AddressingModeField::encode(kMode_MRI), g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); } else { @@ -198,32 +219,39 @@ void InstructionSelector::VisitStore(Node* node) { } DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); ArchOpcode opcode; + ImmediateMode immediate_mode = kNoImmediate; switch (rep) { case kRepFloat32: opcode = kArm64StrS; + immediate_mode = kLoadStoreImm32; break; case kRepFloat64: opcode = kArm64StrD; + immediate_mode = kLoadStoreImm64; break; case kRepBit: // Fall through. case kRepWord8: opcode = kArm64Strb; + immediate_mode = kLoadStoreImm8; break; case kRepWord16: opcode = kArm64Strh; + immediate_mode = kLoadStoreImm16; break; case kRepWord32: opcode = kArm64StrW; + immediate_mode = kLoadStoreImm32; break; case kRepTagged: // Fall through. case kRepWord64: opcode = kArm64Str; + immediate_mode = kLoadStoreImm64; break; default: UNREACHABLE(); return; } - if (g.CanBeImmediate(index, kLoadStoreImm)) { + if (g.CanBeImmediate(index, immediate_mode)) { Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); } else { -- 2.7.4