Commit 04a735c7 authored by balazs.kilvady's avatar balazs.kilvady Committed by Commit bot

MIPS: Improve Lsa/Dlsa implementations.

Make the low level assembler implementation exact and protected to disallow explicit usage.

BUG=

Review URL: https://codereview.chromium.org/1749263002

Cr-Commit-Position: refs/heads/master@{#34673}
parent 899105c0
......@@ -1761,10 +1761,10 @@ void Assembler::rotrv(Register rd, Register rt, Register rs) {
void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
DCHECK(sa < 5 && sa > 0);
DCHECK(sa <= 3);
DCHECK(IsMipsArchVariant(kMips32r6));
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
rd.code() << kRdShift | sa << kSaShift | LSA;
emit(instr);
}
......
......@@ -750,9 +750,6 @@ class Assembler : public AssemblerBase {
void rotr(Register rd, Register rt, uint16_t sa);
void rotrv(Register rd, Register rt, Register rs);
// Address computing instructions with shift.
void lsa(Register rd, Register rt, Register rs, uint8_t sa);
// ------------Memory-instructions-------------
void lb(Register rd, const MemOperand& rs);
......@@ -1154,6 +1151,9 @@ class Assembler : public AssemblerBase {
bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
protected:
// Load Scaled Address instruction.
void lsa(Register rd, Register rt, Register rs, uint8_t sa);
// 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
// the relocation info.
......
......@@ -1148,8 +1148,9 @@ void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
DCHECK(sa >= 1 && sa <= 31);
if (IsMipsArchVariant(kMips32r6) && sa <= 4) {
lsa(rd, rt, rs, sa);
lsa(rd, rt, rs, sa - 1);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
......
......@@ -647,8 +647,12 @@ class MacroAssembler: public Assembler {
#undef DEFINE_INSTRUCTION2
#undef DEFINE_INSTRUCTION3
// Load Scaled Address instructions. Parameter sa (shift argument) must be
// between [1, 31] (inclusive). On pre-r6 architectures the scratch register
// may be clobbered.
void Lsa(Register rd, Register rs, Register rt, uint8_t sa,
Register scratch = at);
void Pref(int32_t hint, const MemOperand& rs);
......@@ -1790,7 +1794,7 @@ void MacroAssembler::GenerateSwitchTable(Register index, size_t case_count,
if (kArchVariant >= kMips32r6) {
BlockTrampolinePoolFor(case_count + 5);
addiupc(at, 5);
lsa(at, at, index, kPointerSizeLog2);
Lsa(at, at, index, kPointerSizeLog2);
lw(at, MemOperand(at));
} else {
Label here;
......
......@@ -1905,20 +1905,20 @@ void Assembler::dsra32(Register rd, Register rt, uint16_t sa) {
void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
DCHECK(sa < 5 && sa > 0);
DCHECK(sa <= 3);
DCHECK(kArchVariant == kMips64r6);
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
rd.code() << kRdShift | sa << kSaShift | LSA;
emit(instr);
}
void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) {
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
DCHECK(sa < 5 && sa > 0);
DCHECK(sa <= 3);
DCHECK(kArchVariant == kMips64r6);
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << kSaShift | DLSA;
Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
rd.code() << kRdShift | sa << kSaShift | DLSA;
emit(instr);
}
......
......@@ -791,10 +791,6 @@ class Assembler : public AssemblerBase {
void dsrl32(Register rt, Register rd, uint16_t sa);
void dsra32(Register rt, Register rd, uint16_t sa);
// Address computing instructions with shift.
void lsa(Register rd, Register rt, Register rs, uint8_t sa);
void dlsa(Register rd, Register rt, Register rs, uint8_t sa);
// ------------Memory-instructions-------------
void lb(Register rd, const MemOperand& rs);
......@@ -1209,6 +1205,10 @@ class Assembler : public AssemblerBase {
bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
protected:
// Load Scaled Address instructions.
void lsa(Register rd, Register rt, Register rs, uint8_t sa);
void dlsa(Register rd, Register rt, Register rs, uint8_t sa);
// 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
// the relocation info.
......
......@@ -1294,8 +1294,9 @@ void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
DCHECK(sa >= 1 && sa <= 31);
if (kArchVariant == kMips64r6 && sa <= 4) {
lsa(rd, rt, rs, sa);
lsa(rd, rt, rs, sa - 1);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
......@@ -1307,8 +1308,9 @@ void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
void MacroAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
DCHECK(sa >= 1 && sa <= 31);
if (kArchVariant == kMips64r6 && sa <= 4) {
dlsa(rd, rt, rs, sa);
dlsa(rd, rt, rs, sa - 1);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
......
......@@ -677,6 +677,9 @@ class MacroAssembler: public Assembler {
#undef DEFINE_INSTRUCTION2
#undef DEFINE_INSTRUCTION3
// Load Scaled Address instructions. Parameter sa (shift argument) must be
// between [1, 31] (inclusive). On pre-r6 architectures the scratch register
// may be clobbered.
void Lsa(Register rd, Register rs, Register rt, uint8_t sa,
Register scratch = at);
void Dlsa(Register rd, Register rs, Register rt, uint8_t sa,
......@@ -1954,7 +1957,7 @@ void MacroAssembler::GenerateSwitchTable(Register index, size_t case_count,
nop();
}
addiupc(at, 5);
dlsa(at, at, index, kPointerSizeLog2);
Dlsa(at, at, index, kPointerSizeLog2);
ld(at, MemOperand(at));
} else {
Label here;
......
......@@ -5360,78 +5360,6 @@ TEST(bal) {
}
static uint32_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
__ lsa(v0, a0, a1, sa);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F1 f = FUNCTION_CAST<F1>(code->entry());
uint32_t res = reinterpret_cast<uint32_t>(
CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
return res;
}
TEST(lsa) {
if (!IsMipsArchVariant(kMips32r6)) return;
CcTest::InitializeVM();
struct TestCaseLsa {
int32_t rt;
int32_t rs;
uint8_t sa;
uint32_t expected_res;
};
struct TestCaseLsa tc[] = {
// rt, rs, sa, expected_res
{0x4, 0x1, 1, 0x6},
{0x4, 0x1, 2, 0x8},
{0x4, 0x1, 3, 0xc},
{0x4, 0x1, 4, 0x14},
{0x0, 0x1, 1, 0x2},
{0x0, 0x1, 2, 0x4},
{0x0, 0x1, 3, 0x8},
{0x0, 0x1, 4, 0x10},
{0x4, 0x0, 1, 0x4},
{0x4, 0x0, 2, 0x4},
{0x4, 0x0, 3, 0x4},
{0x4, 0x0, 4, 0x4},
{0x4, INT32_MAX, 1, 0x2}, // Shift overflow.
{0x4, INT32_MAX >> 1, 2, 0x0}, // Shift overflow.
{0x4, INT32_MAX >> 2, 3, 0xfffffffc}, // Shift overflow.
{0x4, INT32_MAX >> 3, 4, 0xfffffff4}, // Shift overflow.
{INT32_MAX - 1, 0x1, 1, 0x80000000}, // Signed adition overflow.
{INT32_MAX - 3, 0x1, 2, 0x80000000}, // Signed addition overflow.
{INT32_MAX - 7, 0x1, 3, 0x80000000}, // Signed addition overflow.
{INT32_MAX - 15, 0x1, 4, 0x80000000}, // Signed addition overflow.
{-2, 0x1, 1, 0x0}, // Addition overflow.
{-4, 0x1, 2, 0x0}, // Addition overflow.
{-8, 0x1, 3, 0x0}, // Addition overflow.
{-16, 0x1, 4, 0x0}}; // Addition overflow.
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint32_t res = run_lsa(tc[i].rt, tc[i].rs, tc[i].sa);
PrintF("0x%x =? 0x%x == lsa(v0, %x, %x, %hhu)\n", tc[i].expected_res, res,
tc[i].rt, tc[i].rs, tc[i].sa);
CHECK_EQ(tc[i].expected_res, res);
}
}
TEST(Trampoline) {
// Private member of Assembler class.
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
......
......@@ -267,7 +267,7 @@ TEST(jump_tables5) {
masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize));
__ addiupc(at, 6 + 1);
__ lsa(at, at, a0, 2);
__ Lsa(at, at, a0, 2);
__ lw(at, MemOperand(at));
__ jalr(at);
__ nop(); // Branch delay slot nop.
......
......@@ -316,7 +316,7 @@ TEST(jump_tables5) {
masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize));
__ addiupc(at, 6 + 1);
__ dlsa(at, at, a0, 3);
__ Dlsa(at, at, a0, 3);
__ ld(at, MemOperand(at));
__ jalr(at);
__ nop(); // Branch delay slot nop.
......
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