MIPS: Add lsa and dlsa r6 instructions.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#33127}
This commit is contained in:
balazs.kilvady 2016-01-05 11:45:59 -08:00 committed by Commit bot
parent 0cf8254213
commit 8d6899c827
19 changed files with 509 additions and 29 deletions

View File

@ -1700,7 +1700,7 @@ void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
void Assembler::rotrv(Register rd, Register rt, Register rs) {
// Should be called via MacroAssembler::Ror.
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
| (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
@ -1708,6 +1708,16 @@ 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(IsMipsArchVariant(kMips32r6));
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
emit(instr);
}
// ------------Memory-instructions-------------
// Helper for base-reg + offset, when offset is larger than int16.

View File

@ -751,6 +751,8 @@ 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-------------

View File

@ -261,6 +261,7 @@ const int kRdShift = 11;
const int kRdBits = 5;
const int kSaShift = 6;
const int kSaBits = 5;
const int kLsaSaBits = 2;
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
@ -399,6 +400,7 @@ enum SecondaryField : uint32_t {
SRL = ((0U << 3) + 2),
SRA = ((0U << 3) + 3),
SLLV = ((0U << 3) + 4),
LSA = ((0U << 3) + 5),
SRLV = ((0U << 3) + 6),
SRAV = ((0U << 3) + 7),
@ -911,20 +913,21 @@ class Instruction {
FunctionFieldToBitNumber(BREAK) | FunctionFieldToBitNumber(SLL) |
FunctionFieldToBitNumber(SRL) | FunctionFieldToBitNumber(SRA) |
FunctionFieldToBitNumber(SLLV) | FunctionFieldToBitNumber(SRLV) |
FunctionFieldToBitNumber(SRAV) | FunctionFieldToBitNumber(MFHI) |
FunctionFieldToBitNumber(MFLO) | FunctionFieldToBitNumber(MULT) |
FunctionFieldToBitNumber(MULTU) | FunctionFieldToBitNumber(DIV) |
FunctionFieldToBitNumber(DIVU) | FunctionFieldToBitNumber(ADD) |
FunctionFieldToBitNumber(ADDU) | FunctionFieldToBitNumber(SUB) |
FunctionFieldToBitNumber(SUBU) | FunctionFieldToBitNumber(AND) |
FunctionFieldToBitNumber(OR) | FunctionFieldToBitNumber(XOR) |
FunctionFieldToBitNumber(NOR) | FunctionFieldToBitNumber(SLT) |
FunctionFieldToBitNumber(SLTU) | FunctionFieldToBitNumber(TGE) |
FunctionFieldToBitNumber(TGEU) | FunctionFieldToBitNumber(TLT) |
FunctionFieldToBitNumber(TLTU) | FunctionFieldToBitNumber(TEQ) |
FunctionFieldToBitNumber(TNE) | FunctionFieldToBitNumber(MOVZ) |
FunctionFieldToBitNumber(MOVN) | FunctionFieldToBitNumber(MOVCI) |
FunctionFieldToBitNumber(SELEQZ_S) | FunctionFieldToBitNumber(SELNEZ_S);
FunctionFieldToBitNumber(SRAV) | FunctionFieldToBitNumber(LSA) |
FunctionFieldToBitNumber(MFHI) | FunctionFieldToBitNumber(MFLO) |
FunctionFieldToBitNumber(MULT) | FunctionFieldToBitNumber(MULTU) |
FunctionFieldToBitNumber(DIV) | FunctionFieldToBitNumber(DIVU) |
FunctionFieldToBitNumber(ADD) | FunctionFieldToBitNumber(ADDU) |
FunctionFieldToBitNumber(SUB) | FunctionFieldToBitNumber(SUBU) |
FunctionFieldToBitNumber(AND) | FunctionFieldToBitNumber(OR) |
FunctionFieldToBitNumber(XOR) | FunctionFieldToBitNumber(NOR) |
FunctionFieldToBitNumber(SLT) | FunctionFieldToBitNumber(SLTU) |
FunctionFieldToBitNumber(TGE) | FunctionFieldToBitNumber(TGEU) |
FunctionFieldToBitNumber(TLT) | FunctionFieldToBitNumber(TLTU) |
FunctionFieldToBitNumber(TEQ) | FunctionFieldToBitNumber(TNE) |
FunctionFieldToBitNumber(MOVZ) | FunctionFieldToBitNumber(MOVN) |
FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
FunctionFieldToBitNumber(SELNEZ_S);
// Get the encoding type of the instruction.
@ -958,6 +961,11 @@ class Instruction {
return Bits(kSaShift + kSaBits - 1, kSaShift);
}
inline int LsaSaValue() const {
DCHECK(InstructionType() == kRegisterType);
return Bits(kSaShift + kLsaSaBits - 1, kSaShift);
}
inline int FunctionValue() const {
DCHECK(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);

View File

@ -74,6 +74,7 @@ class Decoder {
void PrintFt(Instruction* instr);
void PrintFd(Instruction* instr);
void PrintSa(Instruction* instr);
void PrintLsaSa(Instruction* instr);
void PrintSd(Instruction* instr);
void PrintSs1(Instruction* instr);
void PrintSs2(Instruction* instr);
@ -219,6 +220,13 @@ void Decoder::PrintSa(Instruction* instr) {
}
// Print the integer value of the sa field of a lsa instruction.
void Decoder::PrintLsaSa(Instruction* instr) {
int sa = instr->LsaSaValue() + 1;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
}
// Print the integer value of the rd field, when it is not used as reg.
void Decoder::PrintSd(Instruction* instr) {
int sd = instr->RdValue();
@ -683,11 +691,17 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
case 's': { // 'sa.
switch (format[1]) {
case 'a': {
DCHECK(STRING_STARTS_WITH(format, "sa"));
PrintSa(instr);
return 2;
}
case 'a':
if (format[2] == '2') {
DCHECK(STRING_STARTS_WITH(format, "sa2")); // 'sa2
PrintLsaSa(instr);
return 3;
} else {
DCHECK(STRING_STARTS_WITH(format, "sa"));
PrintSa(instr);
return 2;
}
break;
case 'd': {
DCHECK(STRING_STARTS_WITH(format, "sd"));
PrintSd(instr);
@ -1058,6 +1072,9 @@ void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
case SRAV:
Format(instr, "srav 'rd, 'rt, 'rs");
break;
case LSA:
Format(instr, "lsa 'rd, 'rt, 'rs, 'sa2");
break;
case MFHI:
if (instr->Bits(25, 16) == 0) {
Format(instr, "mfhi 'rd");

View File

@ -1052,6 +1052,19 @@ void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
}
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
if (IsMipsArchVariant(kMips32r6) && sa <= 4) {
lsa(rd, rt, rs, sa);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
sll(tmp, rs, sa);
Addu(rd, rt, tmp);
}
}
// ------------Pseudo-instructions-------------
void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {

View File

@ -627,7 +627,10 @@ class MacroAssembler: public Assembler {
#undef DEFINE_INSTRUCTION
#undef DEFINE_INSTRUCTION2
#undef DEFINE_INSTRUCTION3
void Lsa(Register rd, Register rs, Register rt, uint8_t sa,
Register scratch = at);
void Pref(int32_t hint, const MemOperand& rs);

View File

@ -3514,9 +3514,19 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
SetResult(rd_reg(), static_cast<int32_t>(alu_out));
break;
case SRAV:
alu_out = rt() >> rs();
SetResult(rd_reg(), static_cast<int32_t>(alu_out));
SetResult(rd_reg(), rt() >> rs());
break;
case LSA: {
DCHECK(IsMipsArchVariant(kMips32r6));
int8_t sa = lsa_sa() + 1;
int32_t _rt = rt();
int32_t _rs = rs();
int32_t res = _rs << sa;
res += _rt;
DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
break;
}
case MFHI: // MFHI == CLZ on R6.
if (!IsMipsArchVariant(kMips32r6)) {
DCHECK(sa() == 0);

View File

@ -344,6 +344,7 @@ class Simulator {
inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
inline int32_t sa() const { return currentInstr_->SaValue(); }
inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
inline void SetResult(int32_t rd_reg, int32_t alu_out) {
set_register(rd_reg, alu_out);

View File

@ -1757,7 +1757,7 @@ void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
void Assembler::rotrv(Register rd, Register rt, Register rs) {
// Should be called via MacroAssembler::Ror.
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
| (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
@ -1826,6 +1826,26 @@ 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(kArchVariant == kMips64r6);
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << 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(kArchVariant == kMips64r6);
Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
(rd.code() << kRdShift) | (sa - 1) << kSaShift | DLSA;
emit(instr);
}
// ------------Memory-instructions-------------
// Helper for base-reg + offset, when offset is larger than int16.

View File

@ -770,6 +770,9 @@ 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-------------

View File

@ -237,6 +237,7 @@ const int kRdShift = 11;
const int kRdBits = 5;
const int kSaShift = 6;
const int kSaBits = 5;
const int kLsaSaBits = 2;
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
@ -386,6 +387,7 @@ enum SecondaryField {
SRL = ((0 << 3) + 2),
SRA = ((0 << 3) + 3),
SLLV = ((0 << 3) + 4),
LSA = ((0 << 3) + 5),
SRLV = ((0 << 3) + 6),
SRAV = ((0 << 3) + 7),
@ -402,6 +404,7 @@ enum SecondaryField {
DCLZ_R6 = ((2 << 3) + 2),
DCLO_R6 = ((2 << 3) + 3),
DSLLV = ((2 << 3) + 4),
DLSA = ((2 << 3) + 5),
DSRLV = ((2 << 3) + 6),
DSRAV = ((2 << 3) + 7),
@ -952,6 +955,7 @@ class Instruction {
FunctionFieldToBitNumber(SLLV) | FunctionFieldToBitNumber(DSLLV) |
FunctionFieldToBitNumber(SRLV) | FunctionFieldToBitNumber(DSRLV) |
FunctionFieldToBitNumber(SRAV) | FunctionFieldToBitNumber(DSRAV) |
FunctionFieldToBitNumber(LSA) | FunctionFieldToBitNumber(DLSA) |
FunctionFieldToBitNumber(MFHI) | FunctionFieldToBitNumber(MFLO) |
FunctionFieldToBitNumber(MULT) | FunctionFieldToBitNumber(DMULT) |
FunctionFieldToBitNumber(MULTU) | FunctionFieldToBitNumber(DMULTU) |
@ -1004,6 +1008,11 @@ class Instruction {
return Bits(kSaShift + kSaBits - 1, kSaShift);
}
inline int LsaSaValue() const {
DCHECK(InstructionType() == kRegisterType);
return Bits(kSaShift + kLsaSaBits - 1, kSaShift);
}
inline int FunctionValue() const {
DCHECK(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);

View File

@ -75,6 +75,7 @@ class Decoder {
void PrintFt(Instruction* instr);
void PrintFd(Instruction* instr);
void PrintSa(Instruction* instr);
void PrintLsaSa(Instruction* instr);
void PrintSd(Instruction* instr);
void PrintSs1(Instruction* instr);
void PrintSs2(Instruction* instr);
@ -227,6 +228,13 @@ void Decoder::PrintSa(Instruction* instr) {
}
// Print the integer value of the sa field of a lsa instruction.
void Decoder::PrintLsaSa(Instruction* instr) {
int sa = instr->LsaSaValue() + 1;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
}
// Print the integer value of the rd field, when it is not used as reg.
void Decoder::PrintSd(Instruction* instr) {
int sd = instr->RdValue();
@ -684,11 +692,17 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
case 's': { // 'sa.
switch (format[1]) {
case 'a': {
DCHECK(STRING_STARTS_WITH(format, "sa"));
PrintSa(instr);
return 2;
}
case 'a':
if (format[2] == '2') {
DCHECK(STRING_STARTS_WITH(format, "sa2")); // 'sa2
PrintLsaSa(instr);
return 3;
} else {
DCHECK(STRING_STARTS_WITH(format, "sa"));
PrintSa(instr);
return 2;
}
break;
case 'd': {
DCHECK(STRING_STARTS_WITH(format, "sd"));
PrintSd(instr);
@ -1198,6 +1212,12 @@ void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
case DSRAV:
Format(instr, "dsrav 'rd, 'rt, 'rs");
break;
case LSA:
Format(instr, "lsa 'rd, 'rt, 'rs, 'sa2");
break;
case DLSA:
Format(instr, "dlsa 'rd, 'rt, 'rs, 'sa2");
break;
case MFHI:
if (instr->Bits(25, 16) == 0) {
Format(instr, "mfhi 'rd");

View File

@ -1188,6 +1188,32 @@ void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
}
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
if (kArchVariant == kMips64r6 && sa <= 4) {
lsa(rd, rt, rs, sa);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
sll(tmp, rs, sa);
Addu(rd, rt, tmp);
}
}
void MacroAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
if (kArchVariant == kMips64r6 && sa <= 4) {
dlsa(rd, rt, rs, sa);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
dsll(tmp, rs, sa);
Daddu(rd, rt, tmp);
}
}
// ------------Pseudo-instructions-------------
void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {

View File

@ -655,6 +655,12 @@ class MacroAssembler: public Assembler {
#undef DEFINE_INSTRUCTION
#undef DEFINE_INSTRUCTION2
#undef DEFINE_INSTRUCTION3
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,
Register scratch = at);
void Pref(int32_t hint, const MemOperand& rs);

View File

@ -3494,6 +3494,20 @@ void Simulator::DecodeTypeRegisterSPECIAL() {
case DSRAV:
SetResult(rd_reg(), rt() >> rs());
break;
case LSA: {
DCHECK(kArchVariant == kMips64r6);
int8_t sa = lsa_sa() + 1;
int32_t _rt = static_cast<int32_t>(rt());
int32_t _rs = static_cast<int32_t>(rs());
int32_t res = _rs << sa;
res += _rt;
SetResult(rd_reg(), static_cast<int64_t>(res));
break;
}
case DLSA:
DCHECK(kArchVariant == kMips64r6);
SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
break;
case MFHI: // MFHI == CLZ on R6.
if (kArchVariant != kMips64r6) {
DCHECK(sa() == 0);

View File

@ -379,6 +379,7 @@ class Simulator {
inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
inline int32_t sa() const { return currentInstr_->SaValue(); }
inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
set_register(rd_reg, alu_out);

View File

@ -5351,6 +5351,78 @@ 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;
@ -5382,5 +5454,4 @@ TEST(Trampoline) {
CHECK_EQ(res, 0);
}
#undef __

View File

@ -261,4 +261,85 @@ TEST(jump_tables4) {
}
static uint32_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assembler(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
MacroAssembler* masm = &assembler;
__ Lsa(v0, a0, a1, sa);
__ jr(ra);
__ nop();
CodeDesc desc;
assembler.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) {
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},
{0x4, 0x1, 5, 0x24},
{0x0, 0x1, 1, 0x2},
{0x0, 0x1, 2, 0x4},
{0x0, 0x1, 3, 0x8},
{0x0, 0x1, 4, 0x10},
{0x0, 0x1, 5, 0x20},
{0x4, 0x0, 1, 0x4},
{0x4, 0x0, 2, 0x4},
{0x4, 0x0, 3, 0x4},
{0x4, 0x0, 4, 0x4},
{0x4, 0x0, 5, 0x4},
// Shift overflow.
{0x4, INT32_MAX, 1, 0x2},
{0x4, INT32_MAX >> 1, 2, 0x0},
{0x4, INT32_MAX >> 2, 3, 0xfffffffc},
{0x4, INT32_MAX >> 3, 4, 0xfffffff4},
{0x4, INT32_MAX >> 4, 5, 0xffffffe4},
// Signed addition overflow.
{INT32_MAX - 1, 0x1, 1, 0x80000000},
{INT32_MAX - 3, 0x1, 2, 0x80000000},
{INT32_MAX - 7, 0x1, 3, 0x80000000},
{INT32_MAX - 15, 0x1, 4, 0x80000000},
{INT32_MAX - 31, 0x1, 5, 0x80000000},
// Addition overflow.
{-2, 0x1, 1, 0x0},
{-4, 0x1, 2, 0x0},
{-8, 0x1, 3, 0x0},
{-16, 0x1, 4, 0x0},
{-32, 0x1, 5, 0x0}};
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);
}
}
#undef __

View File

@ -306,4 +306,169 @@ TEST(jump_tables4) {
}
}
static uint64_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assembler(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
MacroAssembler* masm = &assembler;
__ Lsa(v0, a0, a1, sa);
__ jr(ra);
__ nop();
CodeDesc desc;
assembler.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F1 f = FUNCTION_CAST<F1>(code->entry());
uint64_t res = reinterpret_cast<uint64_t>(
CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
return res;
}
TEST(Lsa) {
CcTest::InitializeVM();
struct TestCaseLsa {
int32_t rt;
int32_t rs;
uint8_t sa;
uint64_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},
{0x4, 0x1, 5, 0x24},
{0x0, 0x1, 1, 0x2},
{0x0, 0x1, 2, 0x4},
{0x0, 0x1, 3, 0x8},
{0x0, 0x1, 4, 0x10},
{0x0, 0x1, 5, 0x20},
{0x4, 0x0, 1, 0x4},
{0x4, 0x0, 2, 0x4},
{0x4, 0x0, 3, 0x4},
{0x4, 0x0, 4, 0x4},
{0x4, 0x0, 5, 0x4},
// Shift overflow.
{0x4, INT32_MAX, 1, 0x2},
{0x4, INT32_MAX >> 1, 2, 0x0},
{0x4, INT32_MAX >> 2, 3, 0xfffffffffffffffc},
{0x4, INT32_MAX >> 3, 4, 0xfffffffffffffff4},
{0x4, INT32_MAX >> 4, 5, 0xffffffffffffffe4},
// Signed addition overflow.
{INT32_MAX - 1, 0x1, 1, 0xffffffff80000000},
{INT32_MAX - 3, 0x1, 2, 0xffffffff80000000},
{INT32_MAX - 7, 0x1, 3, 0xffffffff80000000},
{INT32_MAX - 15, 0x1, 4, 0xffffffff80000000},
{INT32_MAX - 31, 0x1, 5, 0xffffffff80000000},
// Addition overflow.
{-2, 0x1, 1, 0x0},
{-4, 0x1, 2, 0x0},
{-8, 0x1, 3, 0x0},
{-16, 0x1, 4, 0x0},
{-32, 0x1, 5, 0x0}};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_lsa(tc[i].rt, tc[i].rs, tc[i].sa);
PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == 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);
}
}
static uint64_t run_dlsa(uint64_t rt, uint64_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assembler(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
MacroAssembler* masm = &assembler;
__ Dlsa(v0, a0, a1, sa);
__ jr(ra);
__ nop();
CodeDesc desc;
assembler.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
::F f = FUNCTION_CAST<::F>(code->entry());
uint64_t res = reinterpret_cast<uint64_t>(
CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
return res;
}
TEST(Dlsa) {
CcTest::InitializeVM();
struct TestCaseLsa {
int64_t rt;
int64_t rs;
uint8_t sa;
uint64_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},
{0x4, 0x1, 5, 0x24},
{0x0, 0x1, 1, 0x2},
{0x0, 0x1, 2, 0x4},
{0x0, 0x1, 3, 0x8},
{0x0, 0x1, 4, 0x10},
{0x0, 0x1, 5, 0x20},
{0x4, 0x0, 1, 0x4},
{0x4, 0x0, 2, 0x4},
{0x4, 0x0, 3, 0x4},
{0x4, 0x0, 4, 0x4},
{0x4, 0x0, 5, 0x4},
// Shift overflow.
{0x4, INT64_MAX, 1, 0x2},
{0x4, INT64_MAX >> 1, 2, 0x0},
{0x4, INT64_MAX >> 2, 3, 0xfffffffffffffffc},
{0x4, INT64_MAX >> 3, 4, 0xfffffffffffffff4},
{0x4, INT64_MAX >> 4, 5, 0xffffffffffffffe4},
// Signed addition overflow.
{INT64_MAX - 1, 0x1, 1, 0x8000000000000000},
{INT64_MAX - 3, 0x1, 2, 0x8000000000000000},
{INT64_MAX - 7, 0x1, 3, 0x8000000000000000},
{INT64_MAX - 15, 0x1, 4, 0x8000000000000000},
{INT64_MAX - 31, 0x1, 5, 0x8000000000000000},
// Addition overflow.
{-2, 0x1, 1, 0x0},
{-4, 0x1, 2, 0x0},
{-8, 0x1, 3, 0x0},
{-16, 0x1, 4, 0x0},
{-32, 0x1, 5, 0x0}};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_dlsa(tc[i].rt, tc[i].rs, tc[i].sa);
PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == Dlsa(v0, %" PRIx64 ", %" PRIx64
", %hhu)\n",
tc[i].expected_res, res, tc[i].rt, tc[i].rs, tc[i].sa);
CHECK_EQ(tc[i].expected_res, res);
}
}
#undef __