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:
parent
0cf8254213
commit
8d6899c827
@ -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.
|
||||
|
@ -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-------------
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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-------------
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 __
|
||||
|
@ -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 __
|
||||
|
@ -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 __
|
||||
|
Loading…
Reference in New Issue
Block a user