MIPS: Implemented PC-relative instructions for R6.

Added: JIC, BEQZC, JIALC, LDPC, LWPC, ALUIPC, ADDIUPC, ALIGN/DAILGN, LWUPC,
AUIPC, BC, BALC. Additional fixed compact branch offset.

TEST=test-assembler-mips[64]/r6_align, r6_dalign, r6_aluipc, r6_lwpc, r6_jic,
                             r6_beqzc, r6_jialc, r6_addiupc, r6_ldpc, r6_lwupc,
                             r6_auipc, r6_bc, r6_balc
BUG=

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

Cr-Commit-Position: refs/heads/master@{#29143}
This commit is contained in:
Ilija.Pavlovic 2015-06-19 04:05:59 -07:00 committed by Commit bot
parent 554bc07d96
commit f0c4edfdc5
16 changed files with 3158 additions and 299 deletions

View File

@ -959,6 +959,20 @@ void Assembler::GenInstrImmediate(Opcode opcode,
}
void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t j) {
DCHECK(rs.is_valid() && (is_uint21(j)));
Instr instr = opcode | (rs.code() << kRsShift) | (j & kImm21Mask);
emit(instr);
}
void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26) {
DCHECK(is_int26(offset26));
Instr instr = opcode | (offset26 & kImm26Mask);
emit(instr);
}
void Assembler::GenInstrJump(Opcode opcode,
uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
@ -1156,6 +1170,19 @@ void Assembler::bal(int16_t offset) {
}
void Assembler::bc(int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrImmediate(BC, offset);
}
void Assembler::balc(int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(BALC, offset);
}
void Assembler::beq(Register rs, Register rt, int16_t offset) {
BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BEQ, rs, rt, offset);
@ -1355,7 +1382,7 @@ void Assembler::beqc(Register rs, Register rt, int16_t offset) {
void Assembler::beqzc(Register rs, int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(!(rs.is(zero_reg)));
Instr instr = BEQZC | (rs.code() << kRsShift) | offset;
Instr instr = POP66 | (rs.code() << kRsShift) | (offset & kImm21Mask);
emit(instr);
}
@ -1370,7 +1397,7 @@ void Assembler::bnec(Register rs, Register rt, int16_t offset) {
void Assembler::bnezc(Register rs, int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(!(rs.is(zero_reg)));
Instr instr = BNEZC | (rs.code() << kRsShift) | offset;
Instr instr = POP76 | (rs.code() << kRsShift) | offset;
emit(instr);
}
@ -1422,29 +1449,18 @@ void Assembler::jalr(Register rs, Register rd) {
}
void Assembler::j_or_jr(int32_t target, Register rs) {
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
(kImm26Bits + kImmFieldShift)) == 0;
if (in_range) {
j(target);
} else {
jr(t9);
}
void Assembler::jic(Register rt, int16_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
Instr instr = POP66 | (JIC << kRsShift) | (rt.code() << kRtShift) |
(offset & kImm16Mask);
emit(instr);
}
void Assembler::jal_or_jalr(int32_t target, Register rs) {
// Get pc of delay slot.
uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
(kImm26Bits+kImmFieldShift)) == 0;
if (in_range) {
jal(target);
} else {
jalr(t9);
}
void Assembler::jialc(Register rt, int16_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(POP76, zero_reg, rt, offset);
}
@ -1757,11 +1773,46 @@ void Assembler::lui(Register rd, int32_t j) {
void Assembler::aui(Register rs, Register rt, int32_t j) {
// This instruction uses same opcode as 'lui'. The difference in encoding is
// 'lui' has zero reg. for rs field.
DCHECK(!(rs.is(zero_reg)));
DCHECK(is_uint16(j));
GenInstrImmediate(LUI, rs, rt, j);
}
// ---------PC-Relative instructions-----------
void Assembler::addiupc(Register rs, int32_t imm19) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(rs.is_valid() && is_int19(imm19));
int32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::lwpc(Register rs, int32_t offset19) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(rs.is_valid() && is_int19(offset19));
int32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::auipc(Register rs, int16_t imm16) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(rs.is_valid() && is_int16(imm16));
int32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::aluipc(Register rs, int16_t imm16) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(rs.is_valid() && is_int16(imm16));
int32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
// -------------Misc-instructions--------------
// Break / Trap instructions.
@ -1937,8 +1988,8 @@ void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
void Assembler::bitswap(Register rd, Register rt) {
DCHECK(kArchVariant == kMips32r6);
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
}
@ -1951,6 +2002,14 @@ void Assembler::pref(int32_t hint, const MemOperand& rs) {
}
void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(is_uint3(bp));
uint16_t sa = (ALIGN << kBp2Bits) | bp;
GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
}
// --------Coprocessor-instructions----------------
// Load, store, move.

View File

@ -645,6 +645,10 @@ class Assembler : public AssemblerBase {
void b(Label* L) { b(branch_offset(L, false)>>2); }
void bal(int16_t offset);
void bal(Label* L) { bal(branch_offset(L, false)>>2); }
void bc(int32_t offset);
void bc(Label* L) { bc(branch_offset(L, false) >> 2); }
void balc(int32_t offset);
void balc(Label* L) { balc(branch_offset(L, false) >> 2); }
void beq(Register rs, Register rt, int16_t offset);
void beq(Register rs, Register rt, Label* L) {
@ -753,8 +757,8 @@ class Assembler : public AssemblerBase {
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
void j_or_jr(int32_t target, Register rs);
void jal_or_jalr(int32_t target, Register rs);
void jic(Register rt, int16_t offset);
void jialc(Register rt, int16_t offset);
// -------Data-processing-instructions---------
@ -819,6 +823,14 @@ class Assembler : public AssemblerBase {
void swr(Register rd, const MemOperand& rs);
// ---------PC-Relative-instructions-----------
void addiupc(Register rs, int32_t imm19);
void lwpc(Register rs, int32_t offset19);
void auipc(Register rs, int16_t imm16);
void aluipc(Register rs, int16_t imm16);
// ----------------Prefetch--------------------
void pref(int32_t hint, const MemOperand& rs);
@ -879,6 +891,7 @@ class Assembler : public AssemblerBase {
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void bitswap(Register rd, Register rt);
void align(Register rd, Register rs, Register rt, uint8_t bp);
// --------Coprocessor-instructions----------------
@ -1347,6 +1360,8 @@ class Assembler : public AssemblerBase {
Register r1,
FPURegister r2,
int32_t j);
void GenInstrImmediate(Opcode opcode, Register rs, int32_t j);
void GenInstrImmediate(Opcode opcode, int32_t offset26);
void GenInstrJump(Opcode opcode,

View File

@ -141,6 +141,8 @@ bool Instruction::IsForbiddenInBranchDelay() const {
case BNEL:
case BLEZL:
case BGTZL:
case BC:
case BALC:
return true;
case REGIMM:
switch (RtFieldRaw()) {
@ -173,6 +175,11 @@ bool Instruction::IsLinkingInstruction() const {
switch (op) {
case JAL:
return true;
case POP76:
if (RsFieldRawNoAssert() == JIALC)
return true; // JIALC
else
return false; // BNEZC
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
@ -272,8 +279,25 @@ Instruction::Type Instruction::InstructionType() const {
switch (FunctionFieldRaw()) {
case INS:
case EXT:
case BITSWAP:
return kRegisterType;
case BSHFL: {
int sa = SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP:
return kRegisterType;
case WSBH:
case SEB:
case SEH:
return kUnsupported;
}
sa >>= kBp2Bits;
switch (sa) {
case ALIGN:
return kRegisterType;
default:
return kUnsupported;
}
}
default:
return kUnsupported;
}
@ -309,8 +333,8 @@ Instruction::Type Instruction::InstructionType() const {
case BNEL:
case BLEZL:
case BGTZL:
case BEQZC:
case BNEZC:
case POP66:
case POP76:
case LB:
case LH:
case LWL:
@ -327,6 +351,9 @@ Instruction::Type Instruction::InstructionType() const {
case LDC1:
case SWC1:
case SDC1:
case PCREL:
case BC:
case BALC:
return kImmediateType;
// 26 bits immediate type instructions. e.g.: j imm26.
case J:

View File

@ -259,9 +259,15 @@ const int kSaBits = 5;
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
const int kBp2Shift = 6;
const int kBp2Bits = 2;
const int kImm16Shift = 0;
const int kImm16Bits = 16;
const int kImm18Shift = 0;
const int kImm18Bits = 18;
const int kImm19Shift = 0;
const int kImm19Bits = 19;
const int kImm21Shift = 0;
const int kImm21Bits = 21;
const int kImm26Shift = 0;
@ -294,6 +300,9 @@ const int kFBtrueBits = 1;
// Instruction bit masks.
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
const int kImm21Mask = ((1 << kImm21Bits) - 1) << kImm21Shift;
const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift;
const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift;
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
@ -311,60 +320,63 @@ const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;
// We use this presentation to stay close to the table representation in
// MIPS32 Architecture For Programmers, Volume II: The MIPS32 Instruction Set.
enum Opcode {
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
BEQZC = ((6 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
BC = ((6 << 3) + 2) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
POP66 = ((6 << 3) + 6) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
BNEZC = ((7 << 3) + 6) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
BALC = ((7 << 3) + 2) << kOpcodeShift,
PCREL = ((7 << 3) + 3) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
POP76 = ((7 << 3) + 6) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
@ -435,7 +447,14 @@ enum SecondaryField {
// SPECIAL3 Encoding of Function Field.
EXT = ((0 << 3) + 0),
INS = ((0 << 3) + 4),
BITSWAP = ((4 << 3) + 0),
BSHFL = ((4 << 3) + 0),
// SPECIAL3 Encoding of sa Field.
BITSWAP = ((0 << 3) + 0),
ALIGN = ((0 << 3) + 2),
WSBH = ((0 << 3) + 2),
SEB = ((2 << 3) + 0),
SEH = ((3 << 3) + 0),
// REGIMM encoding of rt Field.
BLTZ = ((0 << 3) + 0) << 16,
@ -571,6 +590,18 @@ enum SecondaryField {
// COP1X Encoding of Function Field.
MADD_D = ((4 << 3) + 1),
// PCREL Encoding of rt Field.
ADDIUPC = ((0 << 2) + 0),
LWPC = ((0 << 2) + 1),
AUIPC = ((3 << 3) + 6),
ALUIPC = ((3 << 3) + 7),
// POP66 Encoding of rs Field.
JIC = ((0 << 5) + 0),
// POP76 Encoding of rs Field.
JIALC = ((0 << 5) + 0),
NULLSF = 0
};
@ -881,6 +912,11 @@ class Instruction {
return Bits(kFrShift + kFrBits -1, kFrShift);
}
inline int Bp2Value() const {
DCHECK(InstructionType() == kRegisterType);
return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
}
// Float Compare condition code instruction bits.
inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
@ -924,7 +960,6 @@ class Instruction {
}
inline int SaFieldRaw() const {
DCHECK(InstructionType() == kRegisterType);
return InstructionBits() & kSaFieldMask;
}
@ -953,13 +988,24 @@ class Instruction {
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
}
inline int32_t Imm18Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
}
inline int32_t Imm19Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
}
inline int32_t Imm21Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
}
inline int32_t Imm26Value() const {
DCHECK(InstructionType() == kJumpType);
DCHECK((InstructionType() == kJumpType) ||
(InstructionType() == kImmediateType));
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}

View File

@ -81,13 +81,20 @@ class Decoder {
void PrintSs2(Instruction* instr);
void PrintBc(Instruction* instr);
void PrintCc(Instruction* instr);
void PrintBp2(Instruction* instr);
void PrintFunction(Instruction* instr);
void PrintSecondaryField(Instruction* instr);
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
void PrintXImm18(Instruction* instr);
void PrintSImm18(Instruction* instr);
void PrintXImm19(Instruction* instr);
void PrintSImm19(Instruction* instr);
void PrintXImm21(Instruction* instr);
void PrintSImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
void PrintSImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
// Printing of instruction name.
@ -236,6 +243,12 @@ void Decoder::PrintCc(Instruction* instr) {
}
void Decoder::PrintBp2(Instruction* instr) {
int bp2 = instr->Bp2Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
}
// Print 16-bit unsigned immediate value.
void Decoder::PrintUImm16(Instruction* instr) {
int32_t imm = instr->Imm16Value();
@ -257,6 +270,38 @@ void Decoder::PrintXImm16(Instruction* instr) {
}
// Print 18-bit signed immediate value.
void Decoder::PrintSImm18(Instruction* instr) {
int32_t imm =
((instr->Imm18Value()) << (32 - kImm18Bits)) >> (32 - kImm18Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
// Print 18-bit hexa immediate value.
void Decoder::PrintXImm18(Instruction* instr) {
int32_t imm = instr->Imm18Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 19-bit hexa immediate value.
void Decoder::PrintXImm19(Instruction* instr) {
int32_t imm = instr->Imm19Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 19-bit signed immediate value.
void Decoder::PrintSImm19(Instruction* instr) {
int32_t imm19 = instr->Imm19Value();
// set sign
imm19 <<= (32 - kImm19Bits);
imm19 >>= (32 - kImm19Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm19);
}
// Print 21-bit immediate value.
void Decoder::PrintXImm21(Instruction* instr) {
uint32_t imm = instr->Imm21Value();
@ -264,13 +309,33 @@ void Decoder::PrintXImm21(Instruction* instr) {
}
// Print 26-bit immediate value.
// Print 21-bit signed immediate value.
void Decoder::PrintSImm21(Instruction* instr) {
int32_t imm21 = instr->Imm21Value();
// set sign
imm21 <<= (32 - kImm21Bits);
imm21 >>= (32 - kImm21Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm21);
}
// Print 26-bit hex immediate value.
void Decoder::PrintXImm26(Instruction* instr) {
uint32_t imm = instr->Imm26Value() << kImmFieldShift;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 26-bit signed immediate value.
void Decoder::PrintSImm26(Instruction* instr) {
int32_t imm26 = instr->Imm26Value();
// set sign
imm26 <<= (32 - kImm26Bits);
imm26 >>= (32 - kImm26Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm26);
}
// Print 26-bit immediate value.
void Decoder::PrintCode(Instruction* instr) {
if (instr->OpcodeFieldRaw() != SPECIAL)
@ -389,25 +454,75 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
case 'i': { // 'imm16u or 'imm26.
if (format[3] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm16"));
if (format[5] == 's') {
DCHECK(STRING_STARTS_WITH(format, "imm16s"));
PrintSImm16(instr);
} else if (format[5] == 'u') {
DCHECK(STRING_STARTS_WITH(format, "imm16u"));
PrintSImm16(instr);
} else {
DCHECK(STRING_STARTS_WITH(format, "imm16x"));
PrintXImm16(instr);
if (format[4] == '6') {
DCHECK(STRING_STARTS_WITH(format, "imm16"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm16s"));
PrintSImm16(instr);
break;
case 'u':
DCHECK(STRING_STARTS_WITH(format, "imm16u"));
PrintSImm16(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm16x"));
PrintXImm16(instr);
break;
}
return 6;
} else if (format[4] == '8') {
DCHECK(STRING_STARTS_WITH(format, "imm18"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm18s"));
PrintSImm18(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm18x"));
PrintXImm18(instr);
break;
}
return 6;
} else if (format[4] == '9') {
DCHECK(STRING_STARTS_WITH(format, "imm19"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm19s"));
PrintSImm19(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm19x"));
PrintXImm19(instr);
break;
}
return 6;
}
} else if (format[3] == '2' && format[4] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm21"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm21s"));
PrintSImm21(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm21x"));
PrintXImm21(instr);
break;
}
return 6;
} else if (format[3] == '2' && format[4] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm21x"));
PrintXImm21(instr);
return 6;
} else if (format[3] == '2' && format[4] == '6') {
DCHECK(STRING_STARTS_WITH(format, "imm26x"));
PrintXImm26(instr);
DCHECK(STRING_STARTS_WITH(format, "imm26"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm26s"));
PrintSImm26(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm26x"));
PrintXImm26(instr);
break;
}
return 6;
}
}
@ -442,10 +557,23 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
}
}
case 'b': { // 'bc - Special for bc1 cc field.
DCHECK(STRING_STARTS_WITH(format, "bc"));
PrintBc(instr);
return 2;
case 'b': {
switch (format[1]) {
case 'c': { // 'bc - Special for bc1 cc field.
DCHECK(STRING_STARTS_WITH(format, "bc"));
PrintBc(instr);
return 2;
}
case 'p': {
switch (format[2]) {
case '2': { // 'bp2
DCHECK(STRING_STARTS_WITH(format, "bp2"));
PrintBp2(instr);
return 3;
}
}
}
}
}
case 'C': { // 'Cc - Special for c.xx.d cc field.
DCHECK(STRING_STARTS_WITH(format, "Cc"));
@ -941,7 +1069,7 @@ void Decoder::DecodeTypeRegisterSPECIAL2(Instruction* instr) {
void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case INS: {
if (IsMipsArchVariant(kMips32r2)) {
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
} else {
Unknown(instr);
@ -949,18 +1077,45 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
break;
}
case EXT: {
if (IsMipsArchVariant(kMips32r2)) {
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
} else {
Unknown(instr);
}
break;
}
case BITSWAP: {
if (IsMipsArchVariant(kMips32r6)) {
Format(instr, "bitswap 'rd, 'rt");
} else {
Unknown(instr);
case BSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP: {
if (IsMipsArchVariant(kMips32r6)) {
Format(instr, "bitswap 'rd, 'rt");
} else {
Unknown(instr);
}
break;
}
case SEB:
case SEH:
case WSBH:
UNREACHABLE();
break;
default: {
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
if (IsMipsArchVariant(kMips32r6)) {
Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
} else {
Unknown(instr);
}
break;
}
default:
UNREACHABLE();
break;
}
}
}
break;
}
@ -1087,6 +1242,12 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
case BEQ:
Format(instr, "beq 'rs, 'rt, 'imm16u");
break;
case BC:
Format(instr, "bc 'imm26s");
break;
case BALC:
Format(instr, "balc 'imm26s");
break;
case BNE:
Format(instr, "bne 'rs, 'rt, 'imm16u");
break;
@ -1152,13 +1313,17 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
UNREACHABLE();
}
break;
case BEQZC:
if (instr->RsFieldRaw() != 0) {
Format(instr, "beqzc 'rs, 'imm21x");
case POP66:
if (instr->RsValue() == JIC) {
Format(instr, "jic 'rt, 'imm16s");
} else {
Format(instr, "beqzc 'rs, 'imm21s");
}
break;
case BNEZC:
if (instr->RsFieldRaw() != 0) {
case POP76:
if (instr->RsValue() == JIALC) {
Format(instr, "jialc 'rt, 'imm16x");
} else {
Format(instr, "bnezc 'rs, 'imm21x");
}
break;
@ -1270,6 +1435,35 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
case SDC1:
Format(instr, "sdc1 'ft, 'imm16s('rs)");
break;
case PCREL: {
int32_t imm21 = instr->Imm21Value();
// rt field: 5-bits checking
uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) {
case ALUIPC:
Format(instr, "aluipc 'rs, 'imm16s");
break;
case AUIPC:
Format(instr, "auipc 'rs, 'imm16s");
break;
default: {
// rt field: checking of the most significant 2-bits
rt = (imm21 >> kImm19Bits);
switch (rt) {
case LWPC:
Format(instr, "lwpc 'rs, 'imm19s");
break;
case ADDIUPC:
Format(instr, "addiupc 'rs, 'imm19s");
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
default:
printf("a 0x%x \n", instr->OpcodeFieldRaw());
UNREACHABLE();

View File

@ -2169,6 +2169,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
const uint32_t rt_u = static_cast<uint32_t>(rt);
const int32_t rd_reg = instr->RdValue();
const uint32_t sa = instr->SaValue();
const uint8_t bp = instr->Bp2Value();
const int32_t fs_reg = instr->FsValue();
@ -2411,28 +2412,58 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
*alu_out = (rs_u & (mask << lsb)) >> lsb;
break;
}
case BITSWAP: { // Mips32r6 instruction
uint32_t input = static_cast<uint32_t>(rt);
uint32_t output = 0;
uint8_t i_byte, o_byte;
case BSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP: {
uint32_t input = static_cast<uint32_t>(rt);
uint32_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte =
static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
*alu_out = static_cast<int32_t>(output);
break;
}
case SEB:
case SEH:
case WSBH:
UNREACHABLE();
break;
default: {
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
if (bp == 0) {
*alu_out = static_cast<int32_t>(rt);
} else {
uint32_t rt_hi = rt << (8 * bp);
uint32_t rs_lo = rs >> (8 * (4 - bp));
*alu_out = static_cast<int32_t>(rt_hi | rs_lo);
}
break;
}
default:
UNREACHABLE();
break;
}
}
}
*alu_out = static_cast<int32_t>(output);
break;
}
default:
@ -3760,10 +3791,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
set_register(rt_reg, alu_out);
break;
case EXT:
// Ext instr leaves result in Rt, rather than Rd.
set_register(rt_reg, alu_out);
break;
case BITSWAP:
case BSHFL:
set_register(rd_reg, alu_out);
break;
default:
@ -3848,11 +3878,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
int32_t rs_reg = instr->RsValue();
int32_t rs = get_register(instr->RsValue());
uint32_t rs_u = static_cast<uint32_t>(rs);
int32_t rt_reg = instr->RtValue(); // Destination register.
int32_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
int32_t imm19 = instr->Imm19Value();
int32_t imm21 = instr->Imm21Value();
int32_t imm26 = instr->Imm26Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
int64_t ft;
@ -3860,12 +3894,17 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Zero extended immediate.
uint32_t oe_imm16 = 0xffff & imm16;
// Sign extended immediate.
int32_t se_imm16 = imm16;
int32_t se_imm16 = imm16;
int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
int32_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfc000000 : 0);
// Get current pc.
int32_t current_pc = get_pc();
// Next pc.
int32_t next_pc = bad_ra;
// pc increment
int16_t pc_increment;
// Used for conditional branch instructions.
bool do_branch = false;
@ -3979,6 +4018,33 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case BGTZ:
do_branch = rs > 0;
break;
case POP66: {
if (rs_reg) { // BEQZC
int32_t se_imm21 =
static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits));
se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits);
if (rs == 0)
next_pc = current_pc + 4 + (se_imm21 << 2);
else
next_pc = current_pc + 4;
} else { // JIC
next_pc = rt + imm16;
}
break;
}
case BC: {
next_pc = current_pc + 4 + (se_imm26 << 2);
set_pc(next_pc);
pc_modified_ = true;
break;
}
case BALC: {
set_register(31, current_pc + 4);
next_pc = current_pc + 4 + (se_imm26 << 2);
set_pc(next_pc);
pc_modified_ = true;
break;
}
// ------------- Arithmetic instructions.
case ADDI:
if (HaveSameSign(rs, se_imm16)) {
@ -4093,6 +4159,55 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case SDC1:
addr = rs + se_imm16;
break;
// ------------- JIALC and BNEZC instructions.
case POP76:
// Next pc.
next_pc = rt + se_imm16;
// The instruction after the jump is NOT executed.
pc_increment = Instruction::kInstrSize;
if (instr->IsLinkingInstruction()) {
set_register(31, current_pc + pc_increment);
}
set_pc(next_pc);
pc_modified_ = true;
break;
// ------------- PC-Relative instructions.
case PCREL: {
// rt field: checking 5-bits.
uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) {
case ALUIPC:
addr = current_pc + (se_imm16 << 16);
alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
break;
case AUIPC:
alu_out = current_pc + (se_imm16 << 16);
break;
default: {
// rt field: checking the most significant 2-bits.
rt = (imm21 >> kImm19Bits);
switch (rt) {
case LWPC: {
int32_t offset = imm19;
// Set sign.
offset <<= (kOpcodeBits + kRsBits + 2);
offset >>= (kOpcodeBits + kRsBits + 2);
addr = current_pc + (offset << 2);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
alu_out = *ptr;
break;
}
case ADDIUPC:
alu_out = current_pc + (se_imm19 << 2);
break;
default:
UNREACHABLE();
break;
}
}
}
break;
}
default:
UNREACHABLE();
}
@ -4170,6 +4285,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
case PCREL:
set_register(rs_reg, alu_out);
default:
break;
}

View File

@ -967,6 +967,20 @@ void Assembler::GenInstrImmediate(Opcode opcode,
}
void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t j) {
DCHECK(rs.is_valid() && (is_uint21(j)));
Instr instr = opcode | (rs.code() << kRsShift) | (j & kImm21Mask);
emit(instr);
}
void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26) {
DCHECK(is_int26(offset26));
Instr instr = opcode | (offset26 & kImm26Mask);
emit(instr);
}
void Assembler::GenInstrJump(Opcode opcode,
uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
@ -1111,7 +1125,7 @@ int32_t Assembler::branch_offset21_compact(Label* L,
}
}
int32_t offset = target_pos - pc_offset();
int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
DCHECK((offset & 3) == 0);
DCHECK(((offset >> 2) & 0xFFE00000) == 0); // Offset is 21bit width.
@ -1158,6 +1172,19 @@ void Assembler::bal(int16_t offset) {
}
void Assembler::bc(int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
GenInstrImmediate(BC, offset);
}
void Assembler::balc(int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(BALC, offset);
}
void Assembler::beq(Register rs, Register rt, int16_t offset) {
BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BEQ, rs, rt, offset);
@ -1357,7 +1384,7 @@ void Assembler::beqc(Register rs, Register rt, int16_t offset) {
void Assembler::beqzc(Register rs, int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(!(rs.is(zero_reg)));
Instr instr = BEQZC | (rs.code() << kRsShift) | offset;
Instr instr = POP66 | (rs.code() << kRsShift) | (offset & kImm21Mask);
emit(instr);
}
@ -1372,7 +1399,7 @@ void Assembler::bnec(Register rs, Register rt, int16_t offset) {
void Assembler::bnezc(Register rs, int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(!(rs.is(zero_reg)));
Instr instr = BNEZC | (rs.code() << kRsShift) | offset;
Instr instr = POP76 | (rs.code() << kRsShift) | offset;
emit(instr);
}
@ -1428,29 +1455,18 @@ void Assembler::jalr(Register rs, Register rd) {
}
void Assembler::j_or_jr(int64_t target, Register rs) {
// Get pc of delay slot.
uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
(kImm26Bits + kImmFieldShift)) == 0;
if (in_range) {
j(target);
} else {
jr(t9);
}
void Assembler::jic(Register rt, int16_t offset) {
DCHECK(kArchVariant == kMips64r6);
Instr instr = POP66 | (JIC << kRsShift) | (rt.code() << kRtShift) |
(offset & kImm16Mask);
emit(instr);
}
void Assembler::jal_or_jalr(int64_t target, Register rs) {
// Get pc of delay slot.
uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
(kImm26Bits+kImmFieldShift)) == 0;
if (in_range) {
jal(target);
} else {
jalr(t9);
}
void Assembler::jialc(Register rt, int16_t offset) {
DCHECK(kArchVariant == kMips64r6);
positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(POP76, zero_reg, rt, offset);
}
@ -1921,6 +1937,7 @@ void Assembler::lui(Register rd, int32_t j) {
void Assembler::aui(Register rs, Register rt, int32_t j) {
// This instruction uses same opcode as 'lui'. The difference in encoding is
// 'lui' has zero reg. for rs field.
DCHECK(!(rs.is(zero_reg)));
DCHECK(is_uint16(j));
GenInstrImmediate(LUI, rs, rt, j);
}
@ -1984,6 +2001,56 @@ void Assembler::sd(Register rd, const MemOperand& rs) {
}
// ---------PC-Relative instructions-----------
void Assembler::addiupc(Register rs, int32_t imm19) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int19(imm19));
int32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::lwpc(Register rs, int32_t offset19) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int19(offset19));
int32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::lwupc(Register rs, int32_t offset19) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int19(offset19));
int32_t imm21 = LWUPC << kImm19Bits | (offset19 & kImm19Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::ldpc(Register rs, int32_t offset18) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int18(offset18));
int32_t imm21 = LDPC << kImm18Bits | (offset18 & kImm18Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::auipc(Register rs, int16_t imm16) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int16(imm16));
int32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
void Assembler::aluipc(Register rs, int16_t imm16) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(rs.is_valid() && is_int16(imm16));
int32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
GenInstrImmediate(PCREL, rs, imm21);
}
// -------------Misc-instructions--------------
// Break / Trap instructions.
@ -2232,13 +2299,13 @@ void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
void Assembler::bitswap(Register rd, Register rt) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
}
void Assembler::dbitswap(Register rd, Register rt) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBITSWAP);
GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBSHFL);
}
@ -2250,6 +2317,22 @@ void Assembler::pref(int32_t hint, const MemOperand& rs) {
}
void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(is_uint3(bp));
uint16_t sa = (ALIGN << kBp2Bits) | bp;
GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
}
void Assembler::dalign(Register rd, Register rs, Register rt, uint8_t bp) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(is_uint3(bp));
uint16_t sa = (DALIGN << kBp3Bits) | bp;
GenInstrRegister(SPECIAL3, rs, rt, rd, sa, DBSHFL);
}
// --------Coprocessor-instructions----------------
// Load, store, move.

View File

@ -636,6 +636,10 @@ class Assembler : public AssemblerBase {
void b(Label* L) { b(branch_offset(L, false)>>2); }
void bal(int16_t offset);
void bal(Label* L) { bal(branch_offset(L, false)>>2); }
void bc(int32_t offset);
void bc(Label* L) { bc(branch_offset(L, false) >> 2); }
void balc(int32_t offset);
void balc(Label* L) { balc(branch_offset(L, false) >> 2); }
void beq(Register rs, Register rt, int16_t offset);
void beq(Register rs, Register rt, Label* L) {
@ -745,8 +749,8 @@ class Assembler : public AssemblerBase {
void jal(int64_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
void j_or_jr(int64_t target, Register rs);
void jal_or_jalr(int64_t target, Register rs);
void jic(Register rt, int16_t offset);
void jialc(Register rt, int16_t offset);
// -------Data-processing-instructions---------
@ -849,6 +853,16 @@ class Assembler : public AssemblerBase {
void sd(Register rd, const MemOperand& rs);
// ---------PC-Relative-instructions-----------
void addiupc(Register rs, int32_t imm19);
void lwpc(Register rs, int32_t offset19);
void lwupc(Register rs, int32_t offset19);
void ldpc(Register rs, int32_t offset18);
void auipc(Register rs, int16_t imm16);
void aluipc(Register rs, int16_t imm16);
// ----------------Prefetch--------------------
void pref(int32_t hint, const MemOperand& rs);
@ -911,6 +925,8 @@ class Assembler : public AssemblerBase {
void dext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void bitswap(Register rd, Register rt);
void dbitswap(Register rd, Register rt);
void align(Register rd, Register rs, Register rt, uint8_t bp);
void dalign(Register rd, Register rs, Register rt, uint8_t bp);
// --------Coprocessor-instructions----------------
@ -1388,6 +1404,8 @@ class Assembler : public AssemblerBase {
Register r1,
FPURegister r2,
int32_t j);
void GenInstrImmediate(Opcode opcode, Register rs, int32_t j);
void GenInstrImmediate(Opcode opcode, int32_t offset26);
void GenInstrJump(Opcode opcode,

View File

@ -141,6 +141,8 @@ bool Instruction::IsForbiddenInBranchDelay() const {
case BNEL:
case BLEZL:
case BGTZL:
case BC:
case BALC:
return true;
case REGIMM:
switch (RtFieldRaw()) {
@ -173,6 +175,11 @@ bool Instruction::IsLinkingInstruction() const {
switch (op) {
case JAL:
return true;
case POP76:
if (RsFieldRawNoAssert() == JIALC)
return true; // JIALC
else
return false; // BNEZC
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
@ -290,9 +297,43 @@ Instruction::Type Instruction::InstructionType() const {
case INS:
case EXT:
case DEXT:
case BITSWAP:
case DBITSWAP:
return kRegisterType;
case BSHFL: {
int sa = SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP:
return kRegisterType;
case WSBH:
case SEB:
case SEH:
return kUnsupported;
}
sa >>= kBp2Bits;
switch (sa) {
case ALIGN:
return kRegisterType;
default:
return kUnsupported;
}
}
case DBSHFL: {
int sa = SaFieldRaw() >> kSaShift;
switch (sa) {
case DBITSWAP:
return kRegisterType;
case DSBH:
case DSHD:
return kUnsupported;
}
sa = SaFieldRaw() >> kSaShift;
sa >>= kBp3Bits;
switch (sa) {
case DALIGN:
return kRegisterType;
default:
return kUnsupported;
}
}
default:
return kUnsupported;
}
@ -329,8 +370,8 @@ Instruction::Type Instruction::InstructionType() const {
case BNEL:
case BLEZL:
case BGTZL:
case BEQZC:
case BNEZC:
case POP66:
case POP76:
case LB:
case LH:
case LWL:
@ -350,6 +391,9 @@ Instruction::Type Instruction::InstructionType() const {
case LDC1:
case SWC1:
case SDC1:
case PCREL:
case BC:
case BALC:
return kImmediateType;
// 26 bits immediate type instructions. e.g.: j imm26.
case J:

View File

@ -221,9 +221,17 @@ const int kSaBits = 5;
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
const int kBp2Shift = 6;
const int kBp2Bits = 2;
const int kBp3Shift = 6;
const int kBp3Bits = 3;
const int kImm16Shift = 0;
const int kImm16Bits = 16;
const int kImm18Shift = 0;
const int kImm18Bits = 18;
const int kImm19Shift = 0;
const int kImm19Bits = 19;
const int kImm21Shift = 0;
const int kImm21Bits = 21;
const int kImm26Shift = 0;
@ -256,6 +264,9 @@ const int kFBtrueBits = 1;
// Instruction bit masks.
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
const int kImm21Mask = ((1 << kImm21Bits) - 1) << kImm21Shift;
const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift;
const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift;
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
@ -276,72 +287,75 @@ const int64_t kTh16MaskOf64 = (int64_t)0xffff << 16;
// We use this presentation to stay close to the table representation in
// MIPS32 Architecture For Programmers, Volume II: The MIPS32 Instruction Set.
enum Opcode {
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
DAUI = ((3 << 3) + 5) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
DAUI = ((3 << 3) + 5) << kOpcodeShift,
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
DADDIU = ((3 << 3) + 1) << kOpcodeShift,
LDL = ((3 << 3) + 2) << kOpcodeShift,
LDR = ((3 << 3) + 3) << kOpcodeShift,
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
DADDIU = ((3 << 3) + 1) << kOpcodeShift,
LDL = ((3 << 3) + 2) << kOpcodeShift,
LDR = ((3 << 3) + 3) << kOpcodeShift,
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
LWU = ((4 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
LWU = ((4 << 3) + 7) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SDL = ((5 << 3) + 4) << kOpcodeShift,
SDR = ((5 << 3) + 5) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SDL = ((5 << 3) + 4) << kOpcodeShift,
SDR = ((5 << 3) + 5) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
LLD = ((6 << 3) + 4) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
BEQZC = ((6 << 3) + 6) << kOpcodeShift,
LD = ((6 << 3) + 7) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
BC = ((6 << 3) + 2) << kOpcodeShift,
LLD = ((6 << 3) + 4) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
POP66 = ((6 << 3) + 6) << kOpcodeShift,
LD = ((6 << 3) + 7) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
SCD = ((7 << 3) + 4) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
BNEZC = ((7 << 3) + 6) << kOpcodeShift,
SD = ((7 << 3) + 7) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
BALC = ((7 << 3) + 2) << kOpcodeShift,
PCREL = ((7 << 3) + 3) << kOpcodeShift,
SCD = ((7 << 3) + 4) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
POP76 = ((7 << 3) + 6) << kOpcodeShift,
SD = ((7 << 3) + 7) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
@ -443,12 +457,21 @@ enum SecondaryField {
DINSU = ((0 << 3) + 6),
DINS = ((0 << 3) + 7),
BITSWAP = ((4 << 3) + 0),
DBITSWAP = ((4 << 3) + 4),
DSBH = ((4 << 3) + 4),
BSHFL = ((4 << 3) + 0),
DBSHFL = ((4 << 3) + 4),
// SPECIAL3 Encoding of sa Field.
BITSWAP = ((0 << 3) + 0),
ALIGN = ((0 << 3) + 2),
WSBH = ((0 << 3) + 2),
SEB = ((2 << 3) + 0),
SEH = ((3 << 3) + 0),
DBITSWAP = ((0 << 3) + 0),
DALIGN = ((0 << 3) + 1),
DBITSWAP_SA = ((0 << 3) + 0) << kSaShift,
DSBH = ((0 << 3) + 2),
DSHD = ((0 << 3) + 5),
// REGIMM encoding of rt Field.
BLTZ = ((0 << 3) + 0) << 16,
@ -588,6 +611,21 @@ enum SecondaryField {
// COP1X Encoding of Function Field.
MADD_D = ((4 << 3) + 1),
// PCREL Encoding of rt Field.
ADDIUPC = ((0 << 2) + 0),
LWPC = ((0 << 2) + 1),
LWUPC = ((0 << 2) + 2),
LDPC = ((0 << 3) + 6),
// reserved ((1 << 3) + 6),
AUIPC = ((3 << 3) + 6),
ALUIPC = ((3 << 3) + 7),
// POP66 Encoding of rs Field.
JIC = ((0 << 5) + 0),
// POP76 Encoding of rs Field.
JIALC = ((0 << 5) + 0),
NULLSF = 0
};
@ -898,6 +936,16 @@ class Instruction {
return Bits(kFrShift + kFrBits -1, kFrShift);
}
inline int Bp2Value() const {
DCHECK(InstructionType() == kRegisterType);
return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
}
inline int Bp3Value() const {
DCHECK(InstructionType() == kRegisterType);
return Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift);
}
// Float Compare condition code instruction bits.
inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
@ -941,7 +989,6 @@ class Instruction {
}
inline int SaFieldRaw() const {
DCHECK(InstructionType() == kRegisterType);
return InstructionBits() & kSaFieldMask;
}
@ -970,13 +1017,24 @@ class Instruction {
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
}
inline int32_t Imm18Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
}
inline int32_t Imm19Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
}
inline int32_t Imm21Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
}
inline int64_t Imm26Value() const {
DCHECK(InstructionType() == kJumpType);
inline int32_t Imm26Value() const {
DCHECK((InstructionType() == kJumpType) ||
(InstructionType() == kImmediateType));
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}

View File

@ -86,10 +86,17 @@ class Decoder {
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
void PrintXImm18(Instruction* instr);
void PrintSImm18(Instruction* instr);
void PrintXImm19(Instruction* instr);
void PrintSImm19(Instruction* instr);
void PrintXImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
void PrintSImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
void PrintBp2(Instruction* instr);
void PrintBp3(Instruction* instr);
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
@ -251,7 +258,8 @@ void Decoder::PrintUImm16(Instruction* instr) {
// Print 16-bit signed immediate value.
void Decoder::PrintSImm16(Instruction* instr) {
int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
int32_t imm =
((instr->Imm16Value()) << (32 - kImm16Bits)) >> (32 - kImm16Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
@ -263,6 +271,38 @@ void Decoder::PrintXImm16(Instruction* instr) {
}
// Print 18-bit signed immediate value.
void Decoder::PrintSImm18(Instruction* instr) {
int32_t imm =
((instr->Imm18Value()) << (32 - kImm18Bits)) >> (32 - kImm18Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
// Print 18-bit hexa immediate value.
void Decoder::PrintXImm18(Instruction* instr) {
int32_t imm = instr->Imm18Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 19-bit hexa immediate value.
void Decoder::PrintXImm19(Instruction* instr) {
int32_t imm = instr->Imm19Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 19-bit signed immediate value.
void Decoder::PrintSImm19(Instruction* instr) {
int32_t imm19 = instr->Imm19Value();
// set sign
imm19 <<= (32 - kImm19Bits);
imm19 >>= (32 - kImm19Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm19);
}
// Print 21-bit immediate value.
void Decoder::PrintXImm21(Instruction* instr) {
uint32_t imm = instr->Imm21Value();
@ -270,13 +310,35 @@ void Decoder::PrintXImm21(Instruction* instr) {
}
// Print 26-bit immediate value.
// Print 26-bit hex immediate value.
void Decoder::PrintXImm26(Instruction* instr) {
uint32_t imm = static_cast<uint32_t>(instr->Imm26Value()) << kImmFieldShift;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 26-bit signed immediate value.
void Decoder::PrintSImm26(Instruction* instr) {
int32_t imm26 = instr->Imm26Value();
// set sign
imm26 <<= (32 - kImm26Bits);
imm26 >>= (32 - kImm26Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm26);
}
void Decoder::PrintBp2(Instruction* instr) {
int bp2 = instr->Bp2Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
}
void Decoder::PrintBp3(Instruction* instr) {
int bp3 = instr->Bp3Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp3);
}
// Print 26-bit immediate value.
void Decoder::PrintCode(Instruction* instr) {
if (instr->OpcodeFieldRaw() != SPECIAL)
@ -395,25 +457,66 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
case 'i': { // 'imm16u or 'imm26.
if (format[3] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm16"));
if (format[5] == 's') {
DCHECK(STRING_STARTS_WITH(format, "imm16s"));
PrintSImm16(instr);
} else if (format[5] == 'u') {
DCHECK(STRING_STARTS_WITH(format, "imm16u"));
PrintSImm16(instr);
} else {
DCHECK(STRING_STARTS_WITH(format, "imm16x"));
PrintXImm16(instr);
if (format[4] == '6') {
DCHECK(STRING_STARTS_WITH(format, "imm16"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm16s"));
PrintSImm16(instr);
break;
case 'u':
DCHECK(STRING_STARTS_WITH(format, "imm16u"));
PrintSImm16(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm16x"));
PrintXImm16(instr);
break;
}
return 6;
} else if (format[4] == '8') {
DCHECK(STRING_STARTS_WITH(format, "imm18"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm18s"));
PrintSImm18(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm18x"));
PrintXImm18(instr);
break;
}
return 6;
} else if (format[4] == '9') {
DCHECK(STRING_STARTS_WITH(format, "imm19"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm19s"));
PrintSImm19(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm19x"));
PrintXImm19(instr);
break;
}
return 6;
}
return 6;
} else if (format[3] == '2' && format[4] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm21x"));
PrintXImm21(instr);
return 6;
} else if (format[3] == '2' && format[4] == '6') {
DCHECK(STRING_STARTS_WITH(format, "imm26x"));
PrintXImm26(instr);
DCHECK(STRING_STARTS_WITH(format, "imm26"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm26s"));
PrintSImm26(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm26x"));
PrintXImm26(instr);
break;
}
return 6;
}
}
@ -448,10 +551,28 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
}
}
case 'b': { // 'bc - Special for bc1 cc field.
DCHECK(STRING_STARTS_WITH(format, "bc"));
PrintBc(instr);
return 2;
case 'b': {
switch (format[1]) {
case 'c': { // 'bc - Special for bc1 cc field.
DCHECK(STRING_STARTS_WITH(format, "bc"));
PrintBc(instr);
return 2;
}
case 'p': {
switch (format[2]) {
case '2': { // 'bp2
DCHECK(STRING_STARTS_WITH(format, "bp2"));
PrintBp2(instr);
return 3;
}
case '3': { // 'bp3
DCHECK(STRING_STARTS_WITH(format, "bp3"));
PrintBp3(instr);
return 3;
}
}
}
}
}
case 'C': { // 'Cc - Special for c.xx.d cc field.
DCHECK(STRING_STARTS_WITH(format, "Cc"));
@ -1135,17 +1256,65 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
Format(instr, "dext 'rt, 'rs, 'sa, 'ss1");
break;
}
case BITSWAP: {
Format(instr, "bitswap 'rd, 'rt");
case BSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP: {
Format(instr, "bitswap 'rd, 'rt");
break;
}
case SEB:
case SEH:
case WSBH:
UNREACHABLE();
break;
default: {
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
break;
}
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
case DBITSWAP: {
switch (instr->SaFieldRaw()) {
case DBITSWAP_SA:
Format(instr, "dbitswap 'rd, 'rt");
case DBSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case DBITSWAP: {
switch (instr->SaFieldRaw() >> kSaShift) {
case DBITSWAP_SA:
Format(instr, "dbitswap 'rd, 'rt");
break;
default:
UNREACHABLE();
break;
}
break;
default:
}
case DSBH:
case DSHD:
UNREACHABLE();
break;
default: {
sa >>= kBp3Bits;
switch (sa) {
case DALIGN: {
Format(instr, "dalign 'rd, 'rs, 'rt, 'bp3");
break;
}
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
@ -1248,6 +1417,12 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
case BEQ:
Format(instr, "beq 'rs, 'rt, 'imm16u");
break;
case BC:
Format(instr, "bc 'imm26s");
break;
case BALC:
Format(instr, "balc 'imm26s");
break;
case BNE:
Format(instr, "bne 'rs, 'rt, 'imm16u");
break;
@ -1313,13 +1488,17 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
UNREACHABLE();
}
break;
case BEQZC:
if (instr->RsFieldRaw() != 0) {
case POP66:
if (instr->RsValue() == JIC) {
Format(instr, "jic 'rt, 'imm16s");
} else {
Format(instr, "beqzc 'rs, 'imm21x");
}
break;
case BNEZC:
if (instr->RsFieldRaw() != 0) {
case POP76:
if (instr->RsValue() == JIALC) {
Format(instr, "jialc 'rt, 'imm16x");
} else {
Format(instr, "bnezc 'rs, 'imm21x");
}
break;
@ -1454,9 +1633,52 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
case SDC1:
Format(instr, "sdc1 'ft, 'imm16s('rs)");
break;
case PCREL: {
int32_t imm21 = instr->Imm21Value();
// rt field: 5-bits checking
uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) {
case ALUIPC:
Format(instr, "aluipc 'rs, 'imm16s");
break;
case AUIPC:
Format(instr, "auipc 'rs, 'imm16s");
break;
default: {
// rt field: checking of the most significant 3-bits
rt = (imm21 >> kImm18Bits);
switch (rt) {
case LDPC:
Format(instr, "ldpc 'rs, 'imm18s");
break;
default: {
// rt field: checking of the most significant 2-bits
rt = (imm21 >> kImm19Bits);
switch (rt) {
case LWUPC:
Format(instr, "lwupc 'rs, 'imm19s");
break;
case LWPC:
Format(instr, "lwpc 'rs, 'imm19s");
break;
case ADDIUPC:
Format(instr, "addiupc 'rs, 'imm19s");
break;
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
}
break;
}
default:
printf("a 0x%x \n", instr->OpcodeFieldRaw());
UNREACHABLE();
UNREACHABLE();
break;
}
}

View File

@ -2201,6 +2201,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
const uint64_t rt_u = static_cast<uint64_t>(rt);
const int32_t rd_reg = instr->RdValue();
const uint64_t sa = instr->SaValue();
const uint8_t bp2 = instr->Bp2Value();
const uint8_t bp3 = instr->Bp3Value();
const int32_t fs_reg = instr->FsValue();
@ -2335,7 +2337,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
// MIPS spec: If no bits were set in GPR rs, the result written to
// GPR rd is 32.
DCHECK(instr->SaValue() == 1);
*alu_out = base::bits::CountLeadingZeros32(rs_u);
*alu_out =
base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u));
}
break;
case MFLO:
@ -2519,39 +2522,16 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
*alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb);
break;
}
case BITSWAP: { // Mips32r6 instruction
uint32_t input = static_cast<uint32_t>(rt);
uint32_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
*alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
break;
}
case DBITSWAP: {
switch (instr->SaFieldRaw()) {
case DBITSWAP_SA: { // Mips64r6
uint64_t input = static_cast<uint64_t>(rt);
uint64_t output = 0;
case BSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP: {
uint32_t input = static_cast<uint32_t>(rt);
uint32_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 8; i++) {
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
@ -2563,15 +2543,96 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
0x10101LU >>
16);
output = output | ((static_cast<uint64_t>(o_byte) << 56));
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
*alu_out = static_cast<int64_t>(output);
*alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
break;
}
default:
case SEB:
case SEH:
case WSBH:
UNREACHABLE();
break;
default: {
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
if (bp2 == 0) {
*alu_out = static_cast<int32_t>(rt);
} else {
uint64_t rt_hi = rt << (8 * bp2);
uint64_t rs_lo = rs >> (8 * (4 - bp2));
*alu_out = static_cast<int32_t>(rt_hi | rs_lo);
}
break;
}
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
case DBSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case DBITSWAP: {
switch (instr->SaFieldRaw() >> kSaShift) {
case DBITSWAP_SA: { // Mips64r6
uint64_t input = static_cast<uint64_t>(rt);
uint64_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 8; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte =
static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
output = output | ((static_cast<uint64_t>(o_byte) << 56));
input = input >> 8;
}
*alu_out = static_cast<int64_t>(output);
break;
}
}
break;
}
case DSBH:
case DSHD:
UNREACHABLE();
break;
default: {
sa >>= kBp3Bits;
switch (sa) {
case DALIGN: {
if (bp3 == 0) {
*alu_out = static_cast<int64_t>(rt);
} else {
uint64_t rt_hi = rt << (8 * bp3);
uint64_t rs_lo = rs >> (8 * (8 - bp3));
*alu_out = static_cast<int64_t>(rt_hi | rs_lo);
}
break;
}
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
@ -3853,8 +3914,8 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
set_register(rt_reg, alu_out);
TraceRegWr(alu_out);
break;
case BITSWAP:
case DBITSWAP:
case BSHFL:
case DBSHFL:
set_register(rd_reg, alu_out);
TraceRegWr(alu_out);
break;
@ -3933,7 +3994,31 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
break;
case SPECIAL3:
DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
switch (instr->FunctionFieldRaw()) {
case BSHFL: {
int sa = instr->SaValue();
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
break;
}
}
}
case DBSHFL: {
int sa = instr->SaValue();
sa >>= kBp3Bits;
switch (sa) {
case DALIGN: {
DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
break;
}
}
}
default:
DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
break;
}
break;
// Unimplemented opcodes raised an error in the configuration step before,
// so we can use the default here to set the destination register in common
@ -3949,11 +4034,16 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
int32_t rs_reg = instr->RsValue();
int64_t rs = get_register(instr->RsValue());
uint64_t rs_u = static_cast<uint64_t>(rs);
int32_t rt_reg = instr->RtValue(); // Destination register.
int64_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
int32_t imm18 = instr->Imm18Value();
int32_t imm19 = instr->Imm19Value();
int32_t imm21 = instr->Imm21Value();
int32_t imm26 = instr->Imm26Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
int64_t ft = get_fpu_register(ft_reg);
@ -3962,11 +4052,17 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
uint64_t oe_imm16 = 0xffff & imm16;
// Sign extended immediate.
int64_t se_imm16 = imm16;
int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
int64_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0);
// Get current pc.
int64_t current_pc = get_pc();
// Next pc.
int64_t next_pc = bad_ra;
// pc increment
int16_t pc_increment;
// Used for conditional branch instructions.
bool do_branch = false;
@ -4080,6 +4176,33 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case BGTZ:
do_branch = rs > 0;
break;
case POP66: {
if (rs_reg) { // BEQZC
int32_t se_imm21 =
static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits));
se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits);
if (rs == 0)
next_pc = current_pc + 4 + (se_imm21 << 2);
else
next_pc = current_pc + 4;
} else { // JIC
next_pc = rt + imm16;
}
break;
}
case BC: {
next_pc = current_pc + 4 + (se_imm26 << 2);
set_pc(next_pc);
pc_modified_ = true;
break;
}
case BALC: {
set_register(31, current_pc + 4);
next_pc = current_pc + 4 + (se_imm26 << 2);
set_pc(next_pc);
pc_modified_ = true;
break;
}
// ------------- Arithmetic instructions.
case ADDI:
case DADDI:
@ -4213,10 +4336,83 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case SDC1:
addr = rs + se_imm16;
break;
// ------------- JIALC and BNEZC instructions.
case POP76:
// Next pc.
next_pc = rt + se_imm16;
// The instruction after the jump is NOT executed.
pc_increment = Instruction::kInstrSize;
if (instr->IsLinkingInstruction()) {
set_register(31, current_pc + pc_increment);
}
set_pc(next_pc);
pc_modified_ = true;
break;
// ------------- PC-Relative instructions.
case PCREL: {
// rt field: checking 5-bits.
uint8_t rt = (imm21 >> kImm16Bits);
switch (rt) {
case ALUIPC:
addr = current_pc + (se_imm16 << 16);
alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
break;
case AUIPC:
alu_out = current_pc + (se_imm16 << 16);
break;
default: {
// rt field: checking the most significant 3-bits.
rt = (imm21 >> kImm18Bits);
switch (rt) {
case LDPC:
addr =
(current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
alu_out = Read2W(addr, instr);
break;
default: {
// rt field: checking the most significant 2-bits.
rt = (imm21 >> kImm19Bits);
switch (rt) {
case LWUPC: {
int32_t offset = imm19;
// Set sign.
offset <<= (kOpcodeBits + kRsBits + 2);
offset >>= (kOpcodeBits + kRsBits + 2);
addr = current_pc + (offset << 2);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
alu_out = *ptr;
break;
}
case LWPC: {
int32_t offset = imm19;
// Set sign.
offset <<= (kOpcodeBits + kRsBits + 2);
offset >>= (kOpcodeBits + kRsBits + 2);
addr = current_pc + (offset << 2);
int32_t* ptr = reinterpret_cast<int32_t*>(addr);
alu_out = *ptr;
break;
}
case ADDIUPC:
alu_out = current_pc + (se_imm19 << 2);
break;
default:
UNREACHABLE();
break;
}
break;
}
}
break;
}
}
break;
}
default:
UNREACHABLE();
}
// ---------- Raise exceptions triggered.
SignalExceptions();
@ -4298,6 +4494,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
case PCREL:
set_register(rs_reg, alu_out);
default:
break;
}

View File

@ -4262,10 +4262,12 @@ TEST(DIV_FMT) {
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
@ -4343,4 +4345,707 @@ TEST(DIV_FMT) {
}
uint32_t run_align(uint32_t rs_value, uint32_t rt_value, uint8_t bp) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ align(v0, a0, a1, bp);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, rs_value,
rt_value,
0, 0, 0));
return res;
}
TEST(r6_align) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseAlign {
uint32_t rs_value;
uint32_t rt_value;
uint8_t bp;
uint32_t expected_res;
};
struct TestCaseAlign tc[] = {
// rs_value, rt_value, bp, expected_res
{ 0x11223344, 0xaabbccdd, 0, 0xaabbccdd },
{ 0x11223344, 0xaabbccdd, 1, 0xbbccdd11 },
{ 0x11223344, 0xaabbccdd, 2, 0xccdd1122 },
{ 0x11223344, 0xaabbccdd, 3, 0xdd112233 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign);
for (size_t i = 0; i < nr_test_cases; ++i) {
CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value,
tc[i].rt_value, tc[i].bp));
}
}
}
uint32_t PC; // The program counter.
uint32_t run_aluipc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ aluipc(v0, offset);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint32_t) f; // Set the program counter.
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_aluipc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseAluipc {
int16_t offset;
};
struct TestCaseAluipc tc[] = {
// offset
{ -32768 }, // 0x8000
{ -1 }, // 0xFFFF
{ 0 },
{ 1 },
{ 32767 }, // 0x7FFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint32_t res = run_aluipc(tc[i].offset);
// Now, the program_counter (PC) is set.
uint32_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16));
CHECK_EQ(expected_res, res);
}
}
}
uint32_t run_auipc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ auipc(v0, offset);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint32_t) f; // Set the program counter.
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_auipc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseAuipc {
int16_t offset;
};
struct TestCaseAuipc tc[] = {
// offset
{ -32768 }, // 0x8000
{ -1 }, // 0xFFFF
{ 0 },
{ 1 },
{ 32767 }, // 0x7FFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint32_t res = run_auipc(tc[i].offset);
// Now, the program_counter (PC) is set.
uint32_t expected_res = PC + (tc[i].offset << 16);
CHECK_EQ(expected_res, res);
}
}
}
uint32_t run_lwpc(int offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
// 256k instructions; 2^8k
// addiu t7, t0, 0xffff; (0x250fffff)
// ...
// addiu t4, t0, 0x0000; (0x250c0000)
uint32_t addiu_start_1 = 0x25000000;
for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
uint32_t addiu_new = addiu_start_1 + i;
__ dd(addiu_new);
}
__ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register)
__ mov(v0, t8);
// 256k instructions; 2^8k
// addiu t0, t0, 0x0000; (0x25080000)
// ...
// addiu t3, t0, 0xffff; (0x250bffff)
uint32_t addiu_start_2 = 0x25000000;
for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
uint32_t addiu_new = addiu_start_2 + i;
__ dd(addiu_new);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_lwpc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseLwpc {
int offset;
uint32_t expected_res;
};
struct TestCaseLwpc tc[] = {
// offset, expected_res
{ -262144, 0x250fffff }, // offset 0x40000
{ -4, 0x250c0003 },
{ -1, 0x250c0000 },
{ 0, 0xef080000 },
{ 1, 0x03001025 }, // mov(v0, t8)
{ 2, 0x25080000 },
{ 4, 0x25080002 },
{ 262143, 0x250bfffd }, // offset 0x3ffff
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint32_t res = run_lwpc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint32_t run_jic(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label get_program_counter, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t1, 0x66);
__ addiu(v0, v0, 0x1); // <-- offset = -32
__ addiu(v0, v0, 0x2);
__ addiu(v0, v0, 0x10);
__ addiu(v0, v0, 0x20);
__ beq(v0, t1, &stop_execution);
__ nop();
__ bal(&get_program_counter); // t0 <- program counter
__ nop();
__ jic(t0, offset);
__ addiu(v0, v0, 0x100);
__ addiu(v0, v0, 0x200);
__ addiu(v0, v0, 0x1000);
__ addiu(v0, v0, 0x2000); // <--- offset = 16
__ pop(ra);
__ jr(ra);
__ nop();
__ bind(&get_program_counter);
__ mov(t0, ra);
__ jr(ra);
__ nop();
__ bind(&stop_execution);
__ pop(ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_jic) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseJic {
// As rt will be used t0 register which will have value of
// the program counter for the jic instruction.
int16_t offset;
uint32_t expected_res;
};
struct TestCaseJic tc[] = {
// offset, expected_result
{ 16, 0x2033 },
{ 4, 0x3333 },
{ -32, 0x66 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint32_t res = run_jic(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_beqzc(int32_t value, int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label stop_execution;
__ li(v0, 0);
__ li(t1, 0x66);
__ push(ra);
__ addiu(v0, v0, 0x1); // <-- offset = -32
__ addiu(v0, v0, 0x2);
__ addiu(v0, v0, 0x10);
__ addiu(v0, v0, 0x20);
__ beq(v0, t1, &stop_execution);
__ nop();
__ beqzc(a0, offset); // BEQZC rs, offset
__ addiu(v0, v0, 0x1);
__ addiu(v0, v0, 0x100);
__ addiu(v0, v0, 0x200);
__ addiu(v0, v0, 0x1000);
__ addiu(v0, v0, 0x2000); // <--- offset = 16
__ jr(ra);
__ nop();
__ bind(&stop_execution);
__ pop(ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0));
return res;
}
TEST(r6_beqzc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseBeqzc {
uint32_t value;
int32_t offset;
uint32_t expected_res;
};
struct TestCaseBeqzc tc[] = {
// value, offset, expected_res
{ 0x0, -8, 0x66 },
{ 0x0, 0, 0x3334 },
{ 0x0, 1, 0x3333 },
{ 0xabc, 1, 0x3334 },
{ 0x0, 4, 0x2033 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint32_t res = run_beqzc(tc[i].value, tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint32_t run_jialc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label main_block, get_program_counter;
__ push(ra);
__ li(v0, 0);
__ beq(v0, v0, &main_block);
__ nop();
// Block 1
__ addiu(v0, v0, 0x1); // <-- offset = -40
__ addiu(v0, v0, 0x2);
__ jr(ra);
__ nop();
// Block 2
__ addiu(v0, v0, 0x10); // <-- offset = -24
__ addiu(v0, v0, 0x20);
__ jr(ra);
__ nop();
// Block 3 (Main)
__ bind(&main_block);
__ bal(&get_program_counter); // t0 <- program counter
__ nop();
__ jialc(t0, offset);
__ addiu(v0, v0, 0x4);
__ pop(ra);
__ jr(ra);
__ nop();
// Block 4
__ addiu(v0, v0, 0x100); // <-- offset = 20
__ addiu(v0, v0, 0x200);
__ jr(ra);
__ nop();
// Block 5
__ addiu(v0, v0, 0x1000); // <--- offset = 36
__ addiu(v0, v0, 0x2000);
__ jr(ra);
__ nop();
__ bind(&get_program_counter);
__ mov(t0, ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint32_t res =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_jialc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseJialc {
int16_t offset;
uint32_t expected_res;
};
struct TestCaseJialc tc[] = {
// offset, expected_res
{ -40, 0x7 },
{ -24, 0x34 },
{ 20, 0x304 },
{ 36, 0x3004 }
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint32_t res = run_jialc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_addiupc(int32_t imm19) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ addiupc(v0, imm19);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint32_t) f; // Set the program counter.
uint32_t rs =
reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, imm19, 0, 0, 0, 0));
return rs;
}
TEST(r6_addiupc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseAddiupc {
int32_t imm19;
};
struct TestCaseAddiupc tc[] = {
// imm19
{ -262144 }, // 0x40000
{ -1 }, // 0x7FFFF
{ 0 },
{ 1 }, // 0x00001
{ 262143 } // 0x3FFFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint32_t res = run_addiupc(tc[i].imm19);
// Now, the program_counter (PC) is set.
uint32_t expected_res = PC + (tc[i].imm19 << 2);
CHECK_EQ(expected_res, res);
}
}
}
int32_t run_bc(int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label continue_1, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t8, 0);
__ li(t9, 2); // A condition for stopping execution.
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -100; i <= -11; ++i) {
__ dd(instruction_addiu);
}
__ addiu(t8, t8, 1); // -10
__ beq(t8, t9, &stop_execution); // -9
__ nop(); // -8
__ beq(t8, t8, &continue_1); // -7
__ nop(); // -6
__ bind(&stop_execution);
__ pop(ra); // -5, -4
__ jr(ra); // -3
__ nop(); // -2
__ bind(&continue_1);
__ bc(offset); // -1
for (int32_t i = 0; i <= 99; ++i) {
__ dd(instruction_addiu);
}
__ pop(ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
int32_t res =
reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_bc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseBc {
int32_t offset;
int32_t expected_res;
};
struct TestCaseBc tc[] = {
// offset, expected_result
{ -100, (abs(-100) - 10) * 2 },
{ -11, (abs(-100) - 10 + 1) },
{ 0, (abs(-100) - 10 + 1 + 99) },
{ 1, (abs(-100) - 10 + 99) },
{ 99, (abs(-100) - 10 + 1) },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc);
for (size_t i = 0; i < nr_test_cases; ++i) {
int32_t res = run_bc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
int32_t run_balc(int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label continue_1, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t8, 0);
__ li(t9, 2); // A condition for stopping execution.
__ beq(t8, t8, &continue_1);
__ nop();
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -117; i <= -57; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra); // -56
__ nop(); // -55
for (int32_t i = -54; i <= -4; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra); // -3
__ nop(); // -2
__ bind(&continue_1);
__ balc(offset); // -1
__ pop(ra); // 0, 1
__ jr(ra); // 2
__ nop(); // 3
for (int32_t i = 4; i <= 44; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
int32_t res =
reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_balc) {
if (IsMipsArchVariant(kMips32r6)) {
CcTest::InitializeVM();
struct TestCaseBalc {
int32_t offset;
int32_t expected_res;
};
struct TestCaseBalc tc[] = {
// offset, expected_result
{ -117, 61 },
{ -54, 51 },
{ 0, 0 },
{ 4, 41 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc);
for (size_t i = 0; i < nr_test_cases; ++i) {
int32_t res = run_balc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
#undef __

View File

@ -45,6 +45,7 @@ using namespace v8::internal;
typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
typedef Object* (*F4)(int64_t x, int64_t y, int64_t p2, int64_t p3, int64_t p4);
// clang-format off
@ -4448,4 +4449,918 @@ TEST(DIV_FMT) {
}
uint64_t run_align(uint64_t rs_value, uint64_t rt_value, uint8_t bp) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ align(v0, a0, a1, bp);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value,
rt_value,
0, 0, 0));
return res;
}
TEST(r6_align) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseAlign {
uint64_t rs_value;
uint64_t rt_value;
uint8_t bp;
uint64_t expected_res;
};
struct TestCaseAlign tc[] = {
// rs_value, rt_value, bp, expected_res
{ 0x11223344, 0xaabbccdd, 0, 0xffffffffaabbccdd },
{ 0x11223344, 0xaabbccdd, 1, 0xffffffffbbccdd11 },
{ 0x11223344, 0xaabbccdd, 2, 0xffffffffccdd1122 },
{ 0x11223344, 0xaabbccdd, 3, 0xffffffffdd112233 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign);
for (size_t i = 0; i < nr_test_cases; ++i) {
CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value,
tc[i].rt_value,
tc[i].bp));
}
}
}
uint64_t run_dalign(uint64_t rs_value, uint64_t rt_value, uint8_t bp) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ dalign(v0, a0, a1, bp);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F4 f = FUNCTION_CAST<F4>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value,
rt_value,
0, 0, 0));
return res;
}
TEST(r6_dalign) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseDalign {
uint64_t rs_value;
uint64_t rt_value;
uint8_t bp;
uint64_t expected_res;
};
struct TestCaseDalign tc[] = {
// rs_value, rt_value, bp, expected_res
{ 0x1122334455667700, 0xaabbccddeeff8899, 0, 0xaabbccddeeff8899 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 1, 0xbbccddeeff889911 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 2, 0xccddeeff88991122 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 3, 0xddeeff8899112233 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 4, 0xeeff889911223344 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 5, 0xff88991122334455 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 6, 0x8899112233445566 },
{ 0x1122334455667700, 0xaabbccddeeff8899, 7, 0x9911223344556677 }
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseDalign);
for (size_t i = 0; i < nr_test_cases; ++i) {
CHECK_EQ(tc[i].expected_res, run_dalign(tc[i].rs_value,
tc[i].rt_value,
tc[i].bp));
}
}
}
uint64_t PC; // The program counter.
uint64_t run_aluipc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ aluipc(v0, offset);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint64_t) f; // Set the program counter.
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_aluipc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseAluipc {
int16_t offset;
};
struct TestCaseAluipc tc[] = {
// offset
{ -32768 }, // 0x8000
{ -1 }, // 0xFFFF
{ 0 },
{ 1 },
{ 32767 }, // 0x7FFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint64_t res = run_aluipc(tc[i].offset);
// Now, the program_counter (PC) is set.
uint64_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16));
CHECK_EQ(expected_res, res);
}
}
}
uint64_t run_auipc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ auipc(v0, offset);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint64_t) f; // Set the program counter.
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_auipc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseAuipc {
int16_t offset;
};
struct TestCaseAuipc tc[] = {
// offset
{ -32768 }, // 0x8000
{ -1 }, // 0xFFFF
{ 0 },
{ 1 },
{ 32767 }, // 0x7FFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint64_t res = run_auipc(tc[i].offset);
// Now, the program_counter (PC) is set.
uint64_t expected_res = PC + (tc[i].offset << 16);
CHECK_EQ(expected_res, res);
}
}
}
uint64_t run_lwpc(int offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
// 256k instructions; 2^8k
// addiu t3, a4, 0xffff; (0x250fffff)
// ...
// addiu t0, a4, 0x0000; (0x250c0000)
uint32_t addiu_start_1 = 0x25000000;
for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
uint32_t addiu_new = addiu_start_1 + i;
__ dd(addiu_new);
}
__ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register)
__ mov(v0, t8);
// 256k instructions; 2^8k
// addiu a4, a4, 0x0000; (0x25080000)
// ...
// addiu a7, a4, 0xffff; (0x250bffff)
uint32_t addiu_start_2 = 0x25000000;
for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
uint32_t addiu_new = addiu_start_2 + i;
__ dd(addiu_new);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_lwpc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseLwpc {
int offset;
uint64_t expected_res;
};
struct TestCaseLwpc tc[] = {
// offset, expected_res
{ -262144, 0x250fffff }, // offset 0x40000
{ -4, 0x250c0003 },
{ -1, 0x250c0000 },
{ 0, 0xffffffffef080000 },
{ 1, 0x03001025 }, // mov(v0, t8)
{ 2, 0x25080000 },
{ 4, 0x25080002 },
{ 262143, 0x250bfffd }, // offset 0x3ffff
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_lwpc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_lwupc(int offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
// 256k instructions; 2^8k
// addiu t3, a4, 0xffff; (0x250fffff)
// ...
// addiu t0, a4, 0x0000; (0x250c0000)
uint32_t addiu_start_1 = 0x25000000;
for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
uint32_t addiu_new = addiu_start_1 + i;
__ dd(addiu_new);
}
__ lwupc(t8, offset); // offset 0; 0xef080000 (t8 register)
__ mov(v0, t8);
// 256k instructions; 2^8k
// addiu a4, a4, 0x0000; (0x25080000)
// ...
// addiu a7, a4, 0xffff; (0x250bffff)
uint32_t addiu_start_2 = 0x25000000;
for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
uint32_t addiu_new = addiu_start_2 + i;
__ dd(addiu_new);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_lwupc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseLwupc {
int offset;
uint64_t expected_res;
};
struct TestCaseLwupc tc[] = {
// offset, expected_res
{ -262144, 0x250fffff }, // offset 0x40000
{ -4, 0x250c0003 },
{ -1, 0x250c0000 },
{ 0, 0xef100000 },
{ 1, 0x03001025 }, // mov(v0, t8)
{ 2, 0x25080000 },
{ 4, 0x25080002 },
{ 262143, 0x250bfffd }, // offset 0x3ffff
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwupc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_lwupc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_jic(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label get_program_counter, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t1, 0x66);
__ addiu(v0, v0, 0x1); // <-- offset = -32
__ addiu(v0, v0, 0x2);
__ addiu(v0, v0, 0x10);
__ addiu(v0, v0, 0x20);
__ beq(v0, t1, &stop_execution);
__ nop();
__ bal(&get_program_counter); // t0 <- program counter
__ nop();
__ jic(t0, offset);
__ addiu(v0, v0, 0x100);
__ addiu(v0, v0, 0x200);
__ addiu(v0, v0, 0x1000);
__ addiu(v0, v0, 0x2000); // <--- offset = 16
__ pop(ra);
__ jr(ra);
__ nop();
__ bind(&get_program_counter);
__ mov(t0, ra);
__ jr(ra);
__ nop();
__ bind(&stop_execution);
__ pop(ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_jic) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseJic {
// As rt will be used t0 register which will have value of
// the program counter for the jic instruction.
int16_t offset;
uint32_t expected_res;
};
struct TestCaseJic tc[] = {
// offset, expected_result
{ 16, 0x2033 },
{ 4, 0x3333 },
{ -32, 0x66 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_jic(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_beqzc(int32_t value, int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label stop_execution;
__ li(v0, 0);
__ li(t1, 0x66);
__ addiu(v0, v0, 0x1); // <-- offset = -8
__ addiu(v0, v0, 0x2);
__ addiu(v0, v0, 0x10);
__ addiu(v0, v0, 0x20);
__ beq(v0, t1, &stop_execution);
__ nop();
__ beqzc(a0, offset);
__ addiu(v0, v0, 0x1);
__ addiu(v0, v0, 0x100);
__ addiu(v0, v0, 0x200);
__ addiu(v0, v0, 0x1000);
__ addiu(v0, v0, 0x2000); // <--- offset = 4
__ jr(ra);
__ nop();
__ bind(&stop_execution);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0));
return res;
}
TEST(r6_beqzc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseBeqzc {
uint32_t value;
int32_t offset;
uint32_t expected_res;
};
struct TestCaseBeqzc tc[] = {
// value, offset, expected_res
{ 0x0, -8, 0x66 },
{ 0x0, 0, 0x3334 },
{ 0x0, 1, 0x3333 },
{ 0xabc, 1, 0x3334 },
{ 0x0, 4, 0x2033 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_beqzc(tc[i].value, tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_jialc(int16_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label main_block, get_program_counter;
__ push(ra);
__ li(v0, 0);
__ beq(v0, v0, &main_block);
__ nop();
// Block 1
__ addiu(v0, v0, 0x1); // <-- offset = -40
__ addiu(v0, v0, 0x2);
__ jr(ra);
__ nop();
// Block 2
__ addiu(v0, v0, 0x10); // <-- offset = -24
__ addiu(v0, v0, 0x20);
__ jr(ra);
__ nop();
// Block 3 (Main)
__ bind(&main_block);
__ bal(&get_program_counter); // t0 <- program counter
__ nop();
__ jialc(t0, offset);
__ addiu(v0, v0, 0x4);
__ pop(ra);
__ jr(ra);
__ nop();
// Block 4
__ addiu(v0, v0, 0x100); // <-- offset = 20
__ addiu(v0, v0, 0x200);
__ jr(ra);
__ nop();
// Block 5
__ addiu(v0, v0, 0x1000); // <--- offset = 36
__ addiu(v0, v0, 0x2000);
__ jr(ra);
__ nop();
__ bind(&get_program_counter);
__ mov(t0, ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_jialc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseJialc {
// As rt will be used t0 register which will have value of
// the program counter for the jialc instruction.
int16_t offset;
uint32_t expected_res;
};
struct TestCaseJialc tc[] = {
// offset, expected_res
{ -40, 0x7 },
{ -24, 0x34 },
{ 20, 0x304 },
{ 36, 0x3004 }
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_jialc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
uint64_t run_addiupc(int32_t imm19) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
__ addiupc(v0, imm19);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
PC = (uint64_t) f; // Set the program counter.
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_addiupc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseAddiupc {
int32_t imm19;
};
struct TestCaseAddiupc tc[] = {
// imm19
{ -262144 }, // 0x40000
{ -1 }, // 0x7FFFF
{ 0 },
{ 1 }, // 0x00001
{ 262143 } // 0x3FFFF
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc);
for (size_t i = 0; i < nr_test_cases; ++i) {
PC = 0;
uint64_t res = run_addiupc(tc[i].imm19);
// Now, the program_counter (PC) is set.
uint64_t expected_res = PC + (tc[i].imm19 << 2);
CHECK_EQ(expected_res, res);
}
}
}
uint64_t run_ldpc(int offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
// 256k instructions; 2 * 2^7k = 2^8k
// addiu t3, a4, 0xffff; (0x250fffff)
// ...
// addiu t0, a4, 0x0000; (0x250c0000)
uint32_t addiu_start_1 = 0x25000000;
for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
uint32_t addiu_new = addiu_start_1 + i;
__ dd(addiu_new);
}
__ ldpc(t8, offset); // offset 0; 0xef080000 (t8 register)
__ mov(v0, t8);
// 256k instructions; 2 * 2^7k = 2^8k
// addiu a4, a4, 0x0000; (0x25080000)
// ...
// addiu a7, a4, 0xffff; (0x250bffff)
uint32_t addiu_start_2 = 0x25000000;
for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
uint32_t addiu_new = addiu_start_2 + i;
__ dd(addiu_new);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
uint64_t res =
reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_ldpc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseLdpc {
int offset;
uint64_t expected_res;
};
struct TestCaseLdpc tc[] = {
// offset, expected_res
{ -131072, 0x250ffffe250fffff },
{ -4, 0x250c0006250c0007 },
{ -1, 0x250c0000250c0001 },
{ 0, 0x03001025ef180000 },
{ 1, 0x2508000125080000 },
{ 4, 0x2508000725080006 },
{ 131071, 0x250bfffd250bfffc },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLdpc);
for (size_t i = 0; i < nr_test_cases; ++i) {
uint64_t res = run_ldpc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
int64_t run_bc(int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label continue_1, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t8, 0);
__ li(t9, 2); // Condition for the stopping execution.
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -100; i <= -11; ++i) {
__ dd(instruction_addiu);
}
__ addiu(t8, t8, 1); // -10
__ beq(t8, t9, &stop_execution); // -9
__ nop(); // -8
__ beq(t8, t8, &continue_1); // -7
__ nop(); // -6
__ bind(&stop_execution);
__ pop(ra); // -5, -4
__ jr(ra); // -3
__ nop(); // -2
__ bind(&continue_1);
__ bc(offset); // -1
for (int32_t i = 0; i <= 99; ++i) {
__ dd(instruction_addiu);
}
__ pop(ra);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
int64_t res =
reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_bc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseBc {
int32_t offset;
int64_t expected_res;
};
struct TestCaseBc tc[] = {
// offset, expected_result
{ -100, (abs(-100) - 10) * 2 },
{ -11, (abs(-100) - 10 + 1) },
{ 0, (abs(-100) - 10 + 1 + 99) },
{ 1, (abs(-100) - 10 + 99) },
{ 99, (abs(-100) - 10 + 1) },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc);
for (size_t i = 0; i < nr_test_cases; ++i) {
int64_t res = run_bc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
int64_t run_balc(int32_t offset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0);
Label continue_1, stop_execution;
__ push(ra);
__ li(v0, 0);
__ li(t8, 0);
__ li(t9, 2); // Condition for stopping execution.
__ beq(t8, t8, &continue_1);
__ nop();
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -117; i <= -57; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra); // -56
__ nop(); // -55
for (int32_t i = -54; i <= -4; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra); // -3
__ nop(); // -2
__ bind(&continue_1);
__ balc(offset); // -1
__ pop(ra); // 0, 1
__ jr(ra); // 2
__ nop(); // 3
for (int32_t i = 4; i <= 44; ++i) {
__ dd(instruction_addiu);
}
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F2 f = FUNCTION_CAST<F2>(code->entry());
int64_t res =
reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
return res;
}
TEST(r6_balc) {
if (kArchVariant == kMips64r6) {
CcTest::InitializeVM();
struct TestCaseBalc {
int32_t offset;
int64_t expected_res;
};
struct TestCaseBalc tc[] = {
// offset, expected_result
{ -117, 61 },
{ -54, 51 },
{ 0, 0 },
{ 4, 41 },
};
size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc);
for (size_t i = 0; i < nr_test_cases; ++i) {
int64_t res = run_balc(tc[i].offset);
CHECK_EQ(tc[i].expected_res, res);
}
}
}
#undef __

View File

@ -217,12 +217,11 @@ TEST(Type0) {
COMPARE(bnvc(a1, a0, -32768),
"60a48000 bnvc a1, a0, -32768");
COMPARE(beqzc(a0, 0),
"d8800000 beqzc a0, 0x0");
COMPARE(beqzc(a0, 0xfffff), // 0x0fffff == 1048575.
"d88fffff beqzc a0, 0xfffff");
COMPARE(beqzc(a0, 0x100000), // 0x100000 == -1048576.
"d8900000 beqzc a0, 0x100000");
COMPARE(beqzc(a0, -1048576), "d8900000 beqzc a0, -1048576");
COMPARE(beqzc(a0, -1), "d89fffff beqzc a0, -1");
COMPARE(beqzc(a0, 0), "d8800000 beqzc a0, 0");
COMPARE(beqzc(a0, 1), "d8800001 beqzc a0, 1");
COMPARE(beqzc(a0, 1048575), "d88fffff beqzc a0, 1048575");
COMPARE(bnezc(a0, 0),
"f8800000 bnezc a0, 0x0");
@ -230,6 +229,18 @@ TEST(Type0) {
"f88fffff bnezc a0, 0xfffff");
COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576.
"f8900000 bnezc a0, 0x100000");
COMPARE(bc(-33554432), "ca000000 bc -33554432");
COMPARE(bc(-1), "cbffffff bc -1");
COMPARE(bc(0), "c8000000 bc 0");
COMPARE(bc(1), "c8000001 bc 1");
COMPARE(bc(33554431), "c9ffffff bc 33554431");
COMPARE(balc(-33554432), "ea000000 balc -33554432");
COMPARE(balc(-1), "ebffffff balc -1");
COMPARE(balc(0), "e8000000 balc 0");
COMPARE(balc(1), "e8000001 balc 1");
COMPARE(balc(33554431), "e9ffffff balc 33554431");
}
COMPARE(addiu(a0, a1, 0x0),
@ -506,7 +517,7 @@ TEST(Type0) {
}
}
if (IsMipsArchVariant(kMips32r2)) {
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
COMPARE(ins_(a0, a1, 31, 1),
"7ca4ffc4 ins a0, a1, 31, 1");
COMPARE(ins_(s6, s7, 30, 2),
@ -534,6 +545,59 @@ TEST(Type0) {
COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6");
COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6");
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0");
COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1");
COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2");
COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0");
COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1");
COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767");
COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768");
COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0");
COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1");
COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767");
COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768");
COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(lwpc(t1, 0), "ed280000 lwpc t1, 0");
COMPARE(lwpc(t1, 4), "ed280004 lwpc t1, 4");
COMPARE(lwpc(t1, -4), "ed2ffffc lwpc t1, -4");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(jic(t0, -32768), "d8088000 jic t0, -32768");
COMPARE(jic(t0, -1), "d808ffff jic t0, -1");
COMPARE(jic(t0, 0), "d8080000 jic t0, 0");
COMPARE(jic(t0, 4), "d8080004 jic t0, 4");
COMPARE(jic(t0, 32767), "d8087fff jic t0, 32767");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143");
COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1");
COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0");
COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1");
COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000");
COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff");
COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0");
COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1");
COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff");
}
VERIFY_RUN();
}

View File

@ -311,6 +311,18 @@ TEST(Type0) {
"f88fffff bnezc a0, 0xfffff");
COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576.
"f8900000 bnezc a0, 0x100000");
COMPARE(bc(-33554432), "ca000000 bc -33554432");
COMPARE(bc(-1), "cbffffff bc -1");
COMPARE(bc(0), "c8000000 bc 0");
COMPARE(bc(1), "c8000001 bc 1");
COMPARE(bc(33554431), "c9ffffff bc 33554431");
COMPARE(balc(-33554432), "ea000000 balc -33554432");
COMPARE(balc(-1), "ebffffff balc -1");
COMPARE(balc(0), "e8000000 balc 0");
COMPARE(balc(1), "e8000001 balc 1");
COMPARE(balc(33554431), "e9ffffff balc 33554431");
}
COMPARE(addiu(a0, a1, 0x0),
@ -685,6 +697,88 @@ TEST(Type0) {
COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6");
COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6");
if (kArchVariant == kMips64r6) {
COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0");
COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1");
COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2");
COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3");
}
if (kArchVariant == kMips64r6) {
COMPARE(dalign(v0, a0, a1, 0), "7c851224 dalign v0, a0, a1, 0");
COMPARE(dalign(v0, a0, a1, 1), "7c851264 dalign v0, a0, a1, 1");
COMPARE(dalign(v0, a0, a1, 2), "7c8512a4 dalign v0, a0, a1, 2");
COMPARE(dalign(v0, a0, a1, 3), "7c8512e4 dalign v0, a0, a1, 3");
COMPARE(dalign(v0, a0, a1, 4), "7c851324 dalign v0, a0, a1, 4");
COMPARE(dalign(v0, a0, a1, 5), "7c851364 dalign v0, a0, a1, 5");
COMPARE(dalign(v0, a0, a1, 6), "7c8513a4 dalign v0, a0, a1, 6");
COMPARE(dalign(v0, a0, a1, 7), "7c8513e4 dalign v0, a0, a1, 7");
}
if (kArchVariant == kMips64r6) {
COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0");
COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1");
COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767");
COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768");
COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1");
}
if (kArchVariant == kMips64r6) {
COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0");
COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1");
COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767");
COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768");
COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1");
}
if (kArchVariant == kMips64r6) {
COMPARE(lwpc(a5, 0), "ed280000 lwpc a5, 0");
COMPARE(lwpc(a5, 4), "ed280004 lwpc a5, 4");
COMPARE(lwpc(a5, -4), "ed2ffffc lwpc a5, -4");
}
if (kArchVariant == kMips64r6) {
COMPARE(lwupc(a0, -262144), "ec940000 lwupc a0, -262144");
COMPARE(lwupc(a0, -1), "ec97ffff lwupc a0, -1");
COMPARE(lwupc(a0, 0), "ec900000 lwupc a0, 0");
COMPARE(lwupc(a0, 1), "ec900001 lwupc a0, 1");
COMPARE(lwupc(a0, 262143), "ec93ffff lwupc a0, 262143");
}
if (kArchVariant == kMips64r6) {
COMPARE(jic(t0, 16), "d80c0010 jic t0, 16");
COMPARE(jic(t0, 4), "d80c0004 jic t0, 4");
COMPARE(jic(t0, -32), "d80cffe0 jic t0, -32");
}
if (kArchVariant == kMips64r6) {
COMPARE(beqzc(a0, 16), "d8800010 beqzc a0, 0x10");
COMPARE(beqzc(a0, 4), "d8800004 beqzc a0, 0x4");
COMPARE(beqzc(a0, -32), "d89fffe0 beqzc a0, 0x1fffe0");
}
if (kArchVariant == kMips64r6) {
COMPARE(ldpc(v0, 256), "ec580100 ldpc v0, 256");
COMPARE(ldpc(a0, -1), "ec9bffff ldpc a0, -1");
COMPARE(ldpc(a1, 0), "ecb80000 ldpc a1, 0");
}
if (kArchVariant == kMips64r6) {
COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143");
COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1");
COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0");
COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1");
COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144");
}
if (kArchVariant == kMips64r6) {
COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000");
COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff");
COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0");
COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1");
COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff");
}
VERIFY_RUN();
}