MIPS: Implemented PC-relative instructions for R6.
authorIlija.Pavlovic <Ilija.Pavlovic@imgtec.com>
Fri, 19 Jun 2015 11:05:59 +0000 (04:05 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 19 Jun 2015 11:06:14 +0000 (11:06 +0000)
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}

16 files changed:
src/mips/assembler-mips.cc
src/mips/assembler-mips.h
src/mips/constants-mips.cc
src/mips/constants-mips.h
src/mips/disasm-mips.cc
src/mips/simulator-mips.cc
src/mips64/assembler-mips64.cc
src/mips64/assembler-mips64.h
src/mips64/constants-mips64.cc
src/mips64/constants-mips64.h
src/mips64/disasm-mips64.cc
src/mips64/simulator-mips64.cc
test/cctest/test-assembler-mips.cc
test/cctest/test-assembler-mips64.cc
test/cctest/test-disasm-mips.cc
test/cctest/test-disasm-mips64.cc

index fc664aafa524df3888f25ee752a00837515753d3..6831b0b0d370b2e32dd8d625460e90225737f61e 100644 (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.
index 96d5073b942e9cd9818283c326740c838af04751..1f642dec07dbc105048efd84809933f2173bf358 100644 (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,
index bf272875e808bdf7d6eedbf42bda5e4aa1f315ef..0ef64f508d6c950f53c90c940cad6abaaba64c26 100644 (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:
index bdeb8c060b2c0e6f97a41490506d860f5d12f28c..37ac2336bfd184542e5ad5712bdaa5541878921e 100644 (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,
-
-  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.
-
-  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,
-
-  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,
-
-  PREF      =   ((6 << 3) + 3) << kOpcodeShift,
-
-  SWC1      =   ((7 << 3) + 1) << kOpcodeShift,
-  SDC1      =   ((7 << 3) + 5) << kOpcodeShift,
-  BNEZC     =   ((7 << 3) + 6) << kOpcodeShift,
-
-  COP1X     =   ((1 << 4) + 3) << 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,
+
+  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,
+
+  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,
+
+  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,
+
+  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
 };
 
 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);
   }
 
index 381e2f14474e951aa49576f42ab048af8b63ecd2..73169ca00f732d9489384067ccdf5de87a4ac3b1 100644 (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;
         }
-        return 6;
       } else if (format[3] == '2' && format[4] == '1') {
-        DCHECK(STRING_STARTS_WITH(format, "imm21x"));
-        PrintXImm21(instr);
+        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] == '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();
index 1148a7cff6fcd892ace46d608c3d4bf940f30087..16b007e39c9d8af2af61cf5eaebfb390bbd71c98 100644 (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;
-
-          // 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;
-          }
+        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;
+
+                // 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<int32_t>(output);
+              *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;
+              }
+            }
+          }
           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;
   }
index 49e4dd218b06f05d0723aaf788de0b106c5ff233..12f3044d65066a5de04bf8cefeadff7da4d2a956 100644 (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.
index c6d44b59cb70339016febb89dd33cab71336fe01..a83661c087dac4a6d8fe6c46077accda506ffe1d 100644 (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,
index 5ebadb338af47984f6c303539a65e0e2384c9eac..fd183a7b018abddaa9a4c31c321ae876c59d7593 100644 (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:
index a0104da66ed9ffa3b916ee2a978c6bd6055a04e6..0284478c08ed64f4b20ae4b18eb20c1f1b9347b1 100644 (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,
-
-  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,
-
-  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,
-
-  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,
-
-  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,
-
-  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,
-
-  COP1X     =   ((1 << 4) + 3) << 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,
+
+  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,
+
+  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,
+
+  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,
+  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,
+
+  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
 };
 
 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);
   }
 
index 1734913bfdda9bddaba97ebec0800f9114d2962a..3ce2b45380ce7dcd6da4c90a67dec96dfdae34d3 100644 (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;
   }
 }
index fee93a867abbd4a721719d2eb5268fb2d5a761ae..2382f44fb8d731bcebb99e98f257abf8236b3113 100644 (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;
   }
index 3dd294573b8777d6547c8fd06f7a5ef9e88db8d7..af7f58fe858701d78537c69221b47c31f4341c85 100644 (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 __
index f3a94896d0fdd905dda78a7e6ba8f2a74827901c..c4db5b52c14222738919385fc8a51056ab9a4ca6 100644 (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 __
index a60d144109390df3f9bdb2eacb67bdd86a6a578a..9625d032708c556454190d32a477b05606e760e1 100644 (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();
 }
 
index 4d0b44024ca65777cebc1e8f532f3e4288b10258..8b29a9289e42eda8b62d4bd318c3978dae52b316 100644 (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();
 }