Revision: 9259
Author:   [email protected]
Date:     Tue Sep 13 05:12:25 2011
Log:      MIPS: pre-crankshaft updates to assembler and related files. (1/3)

Highlights:
- assembler.h adds FPU definitions used for Crankshaft.
- Support optimization of mips call: jalr->jal
    - includes changes to  set_target_address_at(), support routines.
    - Add 2nd use of Apply() to update target addresses.
- Minor debugging improvement in simulator.

BUG=
TEST=

Review URL: http://codereview.chromium.org/7888003
Patch from Paul Lind <[email protected]>.
http://code.google.com/p/v8/source/detail?r=9259

Modified:
 /branches/bleeding_edge/src/mips/assembler-mips-inl.h
 /branches/bleeding_edge/src/mips/assembler-mips.cc
 /branches/bleeding_edge/src/mips/assembler-mips.h
 /branches/bleeding_edge/src/mips/constants-mips.cc
 /branches/bleeding_edge/src/mips/constants-mips.h
 /branches/bleeding_edge/src/mips/disasm-mips.cc
 /branches/bleeding_edge/src/mips/frames-mips.h
 /branches/bleeding_edge/src/mips/simulator-mips.cc

=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips-inl.h Tue Jun 28 00:31:42 2011 +++ /branches/bleeding_edge/src/mips/assembler-mips-inl.h Tue Sep 13 05:12:25 2011
@@ -83,6 +83,14 @@
 // RelocInfo.

 void RelocInfo::apply(intptr_t delta) {
+  if (IsCodeTarget(rmode_)) {
+    uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask;
+    uint32_t scope2 = reinterpret_cast<uint32_t>(pc_) & ~kImm28Mask;
+
+    if (scope1 != scope2) {
+      Assembler::JumpLabelToJumpRegister(pc_);
+    }
+  }
   if (IsInternalReference(rmode_)) {
     // Absolute code pointer inside code object moves with the code object.
     byte* p = reinterpret_cast<byte*>(pc_);
@@ -218,8 +226,9 @@
   Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
   bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
                          (instr1 & kOpcodeMask) == ORI &&
-                         (instr2 & kOpcodeMask) == SPECIAL &&
-                         (instr2 & kFunctionFieldMask) == JALR);
+                         ((instr2 & kOpcodeMask) == JAL ||
+                          ((instr2 & kOpcodeMask) == SPECIAL &&
+                           (instr2 & kFunctionFieldMask) == JALR)));
   return patched_return;
 }

=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips.cc Wed Aug 31 08:34:33 2011 +++ /branches/bleeding_edge/src/mips/assembler-mips.cc Tue Sep 13 05:12:25 2011
@@ -172,7 +172,8 @@
// -----------------------------------------------------------------------------
 // Implementation of RelocInfo.

-const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
+const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
+                                  1 << RelocInfo::INTERNAL_REFERENCE;


 bool RelocInfo::IsCodedSpecially() {
@@ -544,6 +545,19 @@
   // Checks if the instruction is a jump.
   return opcode == J;
 }
+
+
+bool Assembler::IsJal(Instr instr) {
+  return GetOpcodeField(instr) == JAL;
+}
+
+bool Assembler::IsJr(Instr instr) {
+  return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
+}
+
+bool Assembler::IsJalr(Instr instr) {
+ return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
+}


 bool Assembler::IsLui(Instr instr) {
@@ -939,7 +953,7 @@


 void Assembler::GenInstrJump(Opcode opcode,
-                              uint32_t address) {
+                             uint32_t address) {
   BlockTrampolinePoolScope block_trampoline_pool(this);
   ASSERT(is_uint26(address));
   Instr instr = opcode | address;
@@ -1112,7 +1126,12 @@


 void Assembler::j(int32_t target) {
-  ASSERT(is_uint28(target) && ((target & 3) == 0));
+#if DEBUG
+  // Get pc of delay slot.
+  uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+  ASSERT(in_range && ((target & 3) == 0));
+#endif
   GenInstrJump(J, target >> 2);
 }

@@ -1128,8 +1147,13 @@


 void Assembler::jal(int32_t target) {
+#ifdef DEBUG
+  // Get pc of delay slot.
+  uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+  ASSERT(in_range && ((target & 3) == 0));
+#endif
   positions_recorder()->WriteRecordedPositions();
-  ASSERT(is_uint28(target) && ((target & 3) == 0));
   GenInstrJump(JAL, target >> 2);
 }

@@ -1140,6 +1164,32 @@
   GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
   BlockTrampolinePoolFor(1);  // For associated delay slot.
 }
+
+
+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 = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+  if (in_range) {
+      j(target);
+  } else {
+      jr(t9);
+  }
+}
+
+
+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 = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+  if (in_range) {
+      jal(target);
+  } else {
+      jalr(t9);
+  }
+}


 //-------Data-processing-instructions---------
@@ -1614,6 +1664,13 @@
   GenInstrRegister(COP1, CFC1, rt, fs);
 }

+void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
+  uint64_t i;
+  memcpy(&i, &d, 8);
+
+  *lo = i & 0xffffffff;
+  *hi = i >> 32;
+}

 // Arithmetic.

@@ -1972,10 +2029,15 @@
   }
   if (rinfo.rmode() != RelocInfo::NONE) {
     // Don't record external references unless the heap will be serialized.
-    if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
-        !Serializer::enabled() &&
-        !FLAG_debug_code) {
-      return;
+    if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+#ifdef DEBUG
+      if (!Serializer::enabled()) {
+        Serializer::TooLateToEnableNow();
+      }
+#endif
+      if (!Serializer::enabled() && !emit_debug_code()) {
+        return;
+      }
     }
ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
     if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
@@ -2070,30 +2132,142 @@
 }


+// On Mips, a target address is stored in a lui/ori instruction pair, each
+// of which load 16 bits of the 32-bit address to a register.
+// Patching the address must replace both instr, and flush the i-cache.
+//
+// There is an optimization below, which emits a nop when the address
+// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
+// and possibly removed.
 void Assembler::set_target_address_at(Address pc, Address target) {
-  // On MIPS we patch the address into lui/ori instruction pair.
-
-  // First check we have an li (lui/ori pair).
   Instr instr2 = instr_at(pc + kInstrSize);
+  uint32_t rt_code = GetRtField(instr2);
+  uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+  uint32_t itarget = reinterpret_cast<uint32_t>(target);
+
 #ifdef DEBUG
+ // Check we have the result from a li macro-instruction, using instr pair.
   Instr instr1 = instr_at(pc);
-
-  // Check we have indeed the result from a li with MustUseReg true.
   CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
 #endif

-  uint32_t rt_code = GetRtField(instr2);
-  uint32_t* p = reinterpret_cast<uint32_t*>(pc);
-  uint32_t itarget = reinterpret_cast<uint32_t>(target);
-
-  // lui rt, high-16.
-  // ori rt rt, low-16.
+ // Must use 2 instructions to insure patchable code => just use lui and ori.
+  // lui rt, upper-16.
+  // ori rt rt, lower-16.
   *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
   *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);

-  CPU::FlushICache(pc, 2 * sizeof(int32_t));
+  // The following code is an optimization for the common case of Call()
+  // or Jump() which is load to register, and jump through register:
+  //     li(t9, address); jalr(t9)    (or jr(t9)).
+  // If the destination address is in the same 256 MB page as the call, it
+ // is faster to do a direct jal, or j, rather than jump thru register, since
+  // that lets the cpu pipeline prefetch the target address. However each
+  // time the address above is patched, we have to patch the direct jal/j
+  // instruction, as well as possibly revert to jalr/jr if we now cross a
+  // 256 MB page. Note that with the jal/j instructions, we do not need to
+  // load the register, but that code is left, since it makes it easy to
+  // revert this process. A further optimization could try replacing the
+  // li sequence with nops.
+ // This optimization can only be applied if the rt-code from instr2 is the + // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
+  // mips return. Occasionally this lands after an li().
+
+  Instr instr3 = instr_at(pc + 2 * kInstrSize);
+  uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
+  bool in_range =
+ ((uint32_t)(ipc ^ itarget) >> (kImm26Bits + kImmFieldShift)) == 0; + uint32_t target_field = (uint32_t)(itarget & kJumpAddrMask) >> kImmFieldShift;
+  bool patched_jump = false;
+
+#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
+ // This is a workaround to the 24k core E156 bug (affect some 34k cores also). + // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just + // apply this workaround for all cores so we don't have to identify the core.
+  if (in_range) {
+ // The 24k core E156 bug has some very specific requirements, we only check + // the most simple one: if the address of the delay slot instruction is in
+    // the first or last 32 KB of the 256 MB segment.
+    uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
+    uint32_t ipc_segment_addr = ipc & segment_mask;
+    if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
+      in_range = false;
+  }
+#endif
+
+  if (IsJalr(instr3)) {
+    // Try to convert JALR to JAL.
+    if (in_range && GetRt(instr2) == GetRs(instr3)) {
+      *(p+2) = JAL | target_field;
+      patched_jump = true;
+    }
+  } else if (IsJr(instr3)) {
+    // Try to convert JR to J, skip returns (jr ra).
+    bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
+    if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
+      *(p+2) = J | target_field;
+      patched_jump = true;
+    }
+  } else if (IsJal(instr3)) {
+    if (in_range) {
+      // We are patching an already converted JAL.
+      *(p+2) = JAL | target_field;
+    } else {
+      // Patch JAL, but out of range, revert to JALR.
+      // JALR rs reg is the rt reg specified in the ORI instruction.
+      uint32_t rs_field = GetRt(instr2) << kRsShift;
+ uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
+      *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+    }
+    patched_jump = true;
+  } else if (IsJ(instr3)) {
+    if (in_range) {
+      // We are patching an already converted J (jump).
+      *(p+2) = J | target_field;
+    } else {
+      // Trying patch J, but out of range, just go back to JR.
+ // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
+      uint32_t rs_field = GetRt(instr2) << kRsShift;
+      *(p+2) = SPECIAL | rs_field | JR;
+    }
+    patched_jump = true;
+  }
+
+  CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
 }

+void Assembler::JumpLabelToJumpRegister(Address pc) {
+  // Address pc points to lui/ori instructions.
+  // Jump to label may follow at pc + 2 * kInstrSize.
+  uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+#ifdef DEBUG
+  Instr instr1 = instr_at(pc);
+#endif
+  Instr instr2 = instr_at(pc + 1 * kInstrSize);
+  Instr instr3 = instr_at(pc + 2 * kInstrSize);
+  bool patched = false;
+
+  if (IsJal(instr3)) {
+    ASSERT(GetOpcodeField(instr1) == LUI);
+    ASSERT(GetOpcodeField(instr2) == ORI);
+
+    uint32_t rs_field = GetRt(instr2) << kRsShift;
+    uint32_t rd_field = ra.code() << kRdShift;  // Return-address (ra) reg.
+    *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+    patched = true;
+  } else if (IsJ(instr3)) {
+    ASSERT(GetOpcodeField(instr1) == LUI);
+    ASSERT(GetOpcodeField(instr2) == ORI);
+
+    uint32_t rs_field = GetRt(instr2) << kRsShift;
+    *(p+2) = SPECIAL | rs_field | JR;
+    patched = true;
+  }
+
+  if (patched) {
+      CPU::FlushICache(pc+2, sizeof(Address));
+  }
+}

 } }  // namespace v8::internal

=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips.h Thu Sep 8 12:57:14 2011 +++ /branches/bleeding_edge/src/mips/assembler-mips.h Tue Sep 13 05:12:25 2011
@@ -168,24 +168,36 @@
 // Coprocessor register.
 struct FPURegister {
   static const int kNumRegisters = v8::internal::kNumFPURegisters;
-  // f0 has been excluded from allocation. This is following ia32
-  // where xmm0 is excluded.
-  static const int kNumAllocatableRegisters = 15;
+
+ // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
+  // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
+  // number of Double regs (64-bit regs, or FPU-reg-pairs).
+
+ // A few double registers are reserved: one as a scratch register and one to
+  // hold 0.0.
+  //  f28: 0.0
+  //  f30: scratch register.
+  static const int kNumReservedRegisters = 2;
+  static const int kNumAllocatableRegisters = kNumRegisters / 2 -
+      kNumReservedRegisters;
+

   static int ToAllocationIndex(FPURegister reg) {
-    ASSERT(reg.code() != 0);
     ASSERT(reg.code() % 2 == 0);
-    return (reg.code() / 2) - 1;
+    ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
+    ASSERT(reg.is_valid());
+    return (reg.code() / 2);
   }

   static FPURegister FromAllocationIndex(int index) {
     ASSERT(index >= 0 && index < kNumAllocatableRegisters);
-    return from_code((index + 1) * 2);
+    return from_code(index * 2);
   }

   static const char* AllocationIndexToString(int index) {
     ASSERT(index >= 0 && index < kNumAllocatableRegisters);
     const char* const names[] = {
+      "f0",
       "f2",
       "f4",
       "f6",
@@ -198,9 +210,7 @@
       "f20",
       "f22",
       "f24",
-      "f26",
-      "f28",
-      "f30"
+      "f26"
     };
     return names[index];
   }
@@ -212,6 +222,23 @@

   bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; }
   bool is(FPURegister creg) const { return code_ == creg.code_; }
+  FPURegister low() const {
+    // Find low reg of a Double-reg pair, which is the reg itself.
+    ASSERT(code_ % 2 == 0);  // Specified Double reg must be even.
+    FPURegister reg;
+    reg.code_ = code_;
+    ASSERT(reg.is_valid());
+    return reg;
+  }
+  FPURegister high() const {
+    // Find high reg of a Doubel-reg pair, which is reg + 1.
+    ASSERT(code_ % 2 == 0);  // Specified Double reg must be even.
+    FPURegister reg;
+    reg.code_ = code_ + 1;
+    ASSERT(reg.is_valid());
+    return reg;
+  }
+
   int code() const {
     ASSERT(is_valid());
     return code_;
@@ -228,9 +255,19 @@
   int code_;
 };

+// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
+// 32-bit registers, f0 through f31. When used as 'double' they are used
+// in pairs, starting with the even numbered register. So a double operation
+// on f0 really uses f0 and f1.
+// (Modern mips hardware also supports 32 64-bit registers, via setting
+// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
+// but it is not in common use. Someday we will want to support this in v8.)
+
+// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
 typedef FPURegister DoubleRegister;
-
-const FPURegister no_creg = { -1 };
+typedef FPURegister FloatRegister;
+
+const FPURegister no_freg = { -1 };

 const FPURegister f0 = { 0 };  // Return value in hard float mode.
 const FPURegister f1 = { 1 };
@@ -265,6 +302,8 @@
 const FPURegister f30 = { 30 };
 const FPURegister f31 = { 31 };

+const FPURegister kDoubleRegZero = f28;
+
 // FPU (coprocessor 1) control registers.
 // Currently only FCSR (#31) is implemented.
 struct FPUControlRegister {
@@ -330,6 +369,10 @@
  public:
   explicit MemOperand(Register rn, int32_t offset = 0);
   int32_t offset() const { return offset_; }
+
+  bool OffsetIsInt16Encodable() const {
+    return is_int16(offset_);
+  }

  private:
   int32_t offset_;
@@ -504,6 +547,8 @@
   static Address target_address_at(Address pc);
   static void set_target_address_at(Address pc, Address target);

+  static void JumpLabelToJumpRegister(Address pc);
+
// This sets the branch destination (which gets loaded at the call address).
   // This is for calls and branches within generated code.
   inline static void set_target_at(Address instruction_payload,
@@ -534,9 +579,13 @@
   static const int kExternalTargetSize = 0 * kInstrSize;

   // Number of consecutive instructions used to store 32bit constant.
- // Used in RelocInfo::target_address_address() function to tell serializer
-  // address of the instruction that follows LUI/ORI instruction pair.
-  static const int kInstructionsFor32BitConstant = 2;
+  // Before jump-optimizations, this constant was used in
+ // RelocInfo::target_address_address() function to tell serializer address of + // the instruction that follows LUI/ORI instruction pair. Now, with new jump
+  // optimization, where jump-through-register instruction that usually
+  // follows LUI/ORI pair is substituted with J/JAL, this constant equals
+  // to 3 instructions (LUI+ORI+J/JAL/JR/JALR).
+  static const int kInstructionsFor32BitConstant = 3;

   // Distance between the instruction referring to the address of the call
   // target and the return address.
@@ -623,6 +672,8 @@
   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);


   //-------Data-processing-instructions---------
@@ -892,6 +943,10 @@
   static bool IsLui(Instr instr);
   static bool IsOri(Instr instr);

+  static bool IsJal(Instr instr);
+  static bool IsJr(Instr instr);
+  static bool IsJalr(Instr instr);
+
   static bool IsNop(Instr instr, unsigned int type);
   static bool IsPop(Instr instr);
   static bool IsPush(Instr instr);
@@ -975,6 +1030,8 @@
   bool has_exception() const {
     return internal_trampoline_exception_;
   }
+
+  void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);

   bool is_trampoline_emitted() const {
     return trampoline_emitted_;
=======================================
--- /branches/bleeding_edge/src/mips/constants-mips.cc Mon May 9 07:28:09 2011 +++ /branches/bleeding_edge/src/mips/constants-mips.cc Tue Sep 13 05:12:25 2011
@@ -191,6 +191,7 @@
   const int op = OpcodeFieldRaw();
   switch (op) {
     case JAL:
+      return true;
     case REGIMM:
       switch (RtFieldRaw()) {
         case BGEZAL:
@@ -272,7 +273,7 @@
         case MOVCI:
           return kRegisterType;
         default:
-          UNREACHABLE();
+          return kUnsupported;
       };
       break;
     case SPECIAL2:
@@ -281,7 +282,7 @@
         case CLZ:
           return kRegisterType;
         default:
-          UNREACHABLE();
+          return kUnsupported;
       };
       break;
     case SPECIAL3:
@@ -290,7 +291,7 @@
         case EXT:
           return kRegisterType;
         default:
-          UNREACHABLE();
+          return kUnsupported;
       };
       break;
     case COP1:    // Coprocessor instructions.
@@ -341,7 +342,7 @@
     case JAL:
       return kJumpType;
     default:
-      UNREACHABLE();
+      return kUnsupported;
   };
   return kUnsupported;
 }
=======================================
--- /branches/bleeding_edge/src/mips/constants-mips.h Mon Sep 5 02:04:32 2011 +++ /branches/bleeding_edge/src/mips/constants-mips.h Tue Sep 13 05:12:25 2011
@@ -204,6 +204,10 @@
 static const int kImm28Shift = 0;
 static const int kImm28Bits  = 28;

+// In branches and jumps immediate fields point to words, not bytes,
+// and are therefore shifted by 2.
+static const int kImmFieldShift = 2;
+
 static const int kFsShift       = 11;
 static const int kFsBits        = 5;
 static const int kFtShift       = 16;
@@ -233,7 +237,7 @@
 static const int  kHiMask       =   0xffff << 16;
 static const int  kLoMask       =   0xffff;
 static const int  kSignMask     =   0x80000000;
-
+static const int  kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;

 // ----- MIPS Opcodes and Function Fields.
 // We use this presentation to stay close to the table representation in
@@ -290,12 +294,12 @@
 enum SecondaryField {
   // SPECIAL Encoding of Function Field.
   SLL       =   ((0 << 3) + 0),
+  MOVCI     =   ((0 << 3) + 1),
   SRL       =   ((0 << 3) + 2),
   SRA       =   ((0 << 3) + 3),
   SLLV      =   ((0 << 3) + 4),
   SRLV      =   ((0 << 3) + 6),
   SRAV      =   ((0 << 3) + 7),
-  MOVCI     =   ((0 << 3) + 1),

   JR        =   ((1 << 3) + 0),
   JALR      =   ((1 << 3) + 1),
@@ -498,17 +502,41 @@

 // ----- Coprocessor conditions.
 enum FPUCondition {
-  F,    // False.
-  UN,   // Unordered.
-  EQ,   // Equal.
-  UEQ,  // Unordered or Equal.
-  OLT,  // Ordered or Less Than.
-  ULT,  // Unordered or Less Than.
-  OLE,  // Ordered or Less Than or Equal.
-  ULE   // Unordered or Less Than or Equal.
+  kNoFPUCondition = -1,
+
+  F     = 0,  // False.
+  UN    = 1,  // Unordered.
+  EQ    = 2,  // Equal.
+  UEQ   = 3,  // Unordered or Equal.
+  OLT   = 4,  // Ordered or Less Than.
+  ULT   = 5,  // Unordered or Less Than.
+  OLE   = 6,  // Ordered or Less Than or Equal.
+  ULE   = 7   // Unordered or Less Than or Equal.
 };


+// FPU rounding modes.
+enum FPURoundingMode {
+  RN = 0 << 0,  // Round to Nearest.
+  RZ = 1 << 0,  // Round towards zero.
+  RP = 2 << 0,  // Round towards Plus Infinity.
+  RM = 3 << 0,  // Round towards Minus Infinity.
+
+  // Aliases.
+  kRoundToNearest = RN,
+  kRoundToZero = RZ,
+  kRoundToPlusInf = RP,
+  kRoundToMinusInf = RM
+};
+
+static const uint32_t kFPURoundingModeMask = 3 << 0;
+
+enum CheckForInexactConversion {
+  kCheckForInexactConversion,
+  kDontCheckForInexactConversion
+};
+
+
// -----------------------------------------------------------------------------
 // Hints.

@@ -716,7 +744,7 @@

   inline int32_t Imm26Value() const {
     ASSERT(InstructionType() == kJumpType);
-    return Bits(kImm16Shift + kImm26Bits - 1, kImm26Shift);
+    return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
   }

   // Say if the instruction should not be used in a branch delay slot.
=======================================
--- /branches/bleeding_edge/src/mips/disasm-mips.cc     Mon May  9 07:28:09 2011
+++ /branches/bleeding_edge/src/mips/disasm-mips.cc     Tue Sep 13 05:12:25 2011
@@ -112,7 +112,7 @@
   void PrintUImm16(Instruction* instr);
   void PrintSImm16(Instruction* instr);
   void PrintXImm16(Instruction* instr);
-  void PrintImm26(Instruction* instr);
+  void PrintXImm26(Instruction* instr);
   void PrintCode(Instruction* instr);   // For break and trap instructions.
   // Printing of instruction name.
   void PrintInstructionName(Instruction* instr);
@@ -273,9 +273,9 @@


 // Print 26-bit immediate value.
-void Decoder::PrintImm26(Instruction* instr) {
-  int32_t imm = instr->Imm26Value();
- out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
+void Decoder::PrintXImm26(Instruction* instr) {
+  uint32_t imm = instr->Imm26Value() << kImmFieldShift;
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
 }


@@ -383,9 +383,9 @@
         }
         return 6;
       } else {
-        ASSERT(STRING_STARTS_WITH(format, "imm26"));
-        PrintImm26(instr);
-        return 5;
+        ASSERT(STRING_STARTS_WITH(format, "imm26x"));
+        PrintXImm26(instr);
+        return 6;
       }
     }
     case 'r': {   // 'r: registers.
@@ -926,10 +926,10 @@
 void Decoder::DecodeTypeJump(Instruction* instr) {
   switch (instr->OpcodeFieldRaw()) {
     case J:
-      Format(instr, "j       'imm26");
+      Format(instr, "j       'imm26x");
       break;
     case JAL:
-      Format(instr, "jal     'imm26");
+      Format(instr, "jal     'imm26x");
       break;
     default:
       UNREACHABLE();
@@ -958,6 +958,7 @@
       break;
     }
     default: {
+      Format(instr, "UNSUPPORTED");
       UNSUPPORTED_MIPS();
     }
   }
=======================================
--- /branches/bleeding_edge/src/mips/frames-mips.h      Mon Sep  5 02:04:32 2011
+++ /branches/bleeding_edge/src/mips/frames-mips.h      Tue Sep 13 05:12:25 2011
@@ -87,7 +87,6 @@
 static const int kNumCalleeSavedFPU = 6;
 // Number of registers for which space is reserved in safepoints. Must be a
 // multiple of 8.
-// TODO(mips): Only 8 registers may actually be sufficient. Revisit.
 static const int kNumSafepointRegisters = 24;

 // Define the list of registers actually saved at safepoints.
=======================================
--- /branches/bleeding_edge/src/mips/simulator-mips.cc Mon Sep 5 02:04:32 2011 +++ /branches/bleeding_edge/src/mips/simulator-mips.cc Tue Sep 13 05:12:25 2011
@@ -33,6 +33,7 @@

 #if defined(V8_TARGET_ARCH_MIPS)

+#include "cpu.h"
 #include "disasm.h"
 #include "assembler.h"
 #include "globals.h"    // Need the BitCast.
@@ -1215,6 +1216,8 @@
 int Simulator::ReadW(int32_t addr, Instruction* instr) {
   if (addr >=0 && addr < 0x400) {
     // This has to be a NULL-dereference, drop into debugger.
+    PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
+           addr, reinterpret_cast<intptr_t>(instr));
     MipsDebugger dbg(this);
     dbg.Debug();
   }
@@ -1234,6 +1237,8 @@
 void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
   if (addr >= 0 && addr < 0x400) {
     // This has to be a NULL-dereference, drop into debugger.
+    PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
+           addr, reinterpret_cast<intptr_t>(instr));
     MipsDebugger dbg(this);
     dbg.Debug();
   }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to