From aa00dbdc4064451ec6acab4117fe8e863187b022 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Tue, 13 Sep 2011 12:12:25 +0000 Subject: [PATCH] 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 . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9259 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mips/assembler-mips-inl.h | 13 ++- src/mips/assembler-mips.cc | 214 ++++++++++++++++++++++++++++++++++++++---- src/mips/assembler-mips.h | 83 +++++++++++++--- src/mips/constants-mips.cc | 9 +- src/mips/constants-mips.h | 50 +++++++--- src/mips/disasm-mips.cc | 19 ++-- src/mips/frames-mips.h | 1 - src/mips/simulator-mips.cc | 5 + 8 files changed, 334 insertions(+), 60 deletions(-) diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h index b5ffe73..c4c4fd2 100644 --- a/src/mips/assembler-mips-inl.h +++ b/src/mips/assembler-mips-inl.h @@ -83,6 +83,14 @@ bool Operand::is_reg() const { // RelocInfo. void RelocInfo::apply(intptr_t delta) { + if (IsCodeTarget(rmode_)) { + uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask; + uint32_t scope2 = reinterpret_cast(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(pc_); @@ -218,8 +226,9 @@ bool RelocInfo::IsPatchedReturnSequence() { 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; } diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc index f30f38b..e01a0ca 100644 --- a/src/mips/assembler-mips.cc +++ b/src/mips/assembler-mips.cc @@ -172,7 +172,8 @@ Register ToRegister(int num) { // ----------------------------------------------------------------------------- // Implementation of RelocInfo. -const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE; +const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | + 1 << RelocInfo::INTERNAL_REFERENCE; bool RelocInfo::IsCodedSpecially() { @@ -546,6 +547,19 @@ bool Assembler::IsJ(Instr instr) { } +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) { uint32_t opcode = GetOpcodeField(instr); // Checks if the instruction is a load upper immediate. @@ -939,7 +953,7 @@ void Assembler::GenInstrImmediate(Opcode opcode, 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::bne(Register rs, Register rt, int16_t offset) { 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(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::jr(Register rs) { void Assembler::jal(int32_t target) { +#ifdef DEBUG + // Get pc of delay slot. + uint32_t ipc = reinterpret_cast(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); } @@ -1142,6 +1166,32 @@ 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(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(pc_ + 1 * kInstrSize); + bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0; + + if (in_range) { + jal(target); + } else { + jalr(t9); + } +} + + //-------Data-processing-instructions--------- // Arithmetic. @@ -1614,6 +1664,13 @@ void Assembler::cfc1(Register rt, FPUControlRegister fs) { 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 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { } 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 @@ Address Assembler::target_address_at(Address pc) { } +// 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(pc); + uint32_t itarget = reinterpret_cast(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(pc); - uint32_t itarget = reinterpret_cast(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(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(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(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 diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h index 2c0633f..38e9537 100644 --- a/src/mips/assembler-mips.h +++ b/src/mips/assembler-mips.h @@ -168,24 +168,36 @@ Register ToRegister(int num); // 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 @@ struct FPURegister { "f20", "f22", "f24", - "f26", - "f28", - "f30" + "f26" }; return names[index]; } @@ -212,6 +222,23 @@ struct FPURegister { 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 @@ struct FPURegister { 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; +typedef FPURegister FloatRegister; -const FPURegister no_creg = { -1 }; +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 f29 = { 29 }; 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 { @@ -331,6 +370,10 @@ class MemOperand : public Operand { 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 @@ class Assembler : public AssemblerBase { 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 @@ class Assembler : public AssemblerBase { 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 @@ 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); //-------Data-processing-instructions--------- @@ -892,6 +943,10 @@ class Assembler : public AssemblerBase { 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); @@ -976,6 +1031,8 @@ class Assembler : public AssemblerBase { return internal_trampoline_exception_; } + void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi); + bool is_trampoline_emitted() const { return trampoline_emitted_; } diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc index 96a2333..d0a7af5 100644 --- a/src/mips/constants-mips.cc +++ b/src/mips/constants-mips.cc @@ -191,6 +191,7 @@ bool Instruction::IsLinkingInstruction() const { const int op = OpcodeFieldRaw(); switch (op) { case JAL: + return true; case REGIMM: switch (RtFieldRaw()) { case BGEZAL: @@ -272,7 +273,7 @@ Instruction::Type Instruction::InstructionType() const { case MOVCI: return kRegisterType; default: - UNREACHABLE(); + return kUnsupported; }; break; case SPECIAL2: @@ -281,7 +282,7 @@ Instruction::Type Instruction::InstructionType() const { case CLZ: return kRegisterType; default: - UNREACHABLE(); + return kUnsupported; }; break; case SPECIAL3: @@ -290,7 +291,7 @@ Instruction::Type Instruction::InstructionType() const { case EXT: return kRegisterType; default: - UNREACHABLE(); + return kUnsupported; }; break; case COP1: // Coprocessor instructions. @@ -341,7 +342,7 @@ Instruction::Type Instruction::InstructionType() const { case JAL: return kJumpType; default: - UNREACHABLE(); + return kUnsupported; }; return kUnsupported; } diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h index ede9688..d76ae59 100644 --- a/src/mips/constants-mips.h +++ b/src/mips/constants-mips.h @@ -204,6 +204,10 @@ static const int kImm26Bits = 26; 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 kFunctionFieldMask = 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 Opcode { 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,14 +502,38 @@ inline Condition ReverseCondition(Condition cc) { // ----- 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 }; @@ -716,7 +744,7 @@ class Instruction { 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. diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc index 7df5c41..fde0c58 100644 --- a/src/mips/disasm-mips.cc +++ b/src/mips/disasm-mips.cc @@ -112,7 +112,7 @@ class Decoder { 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 @@ void Decoder::PrintXImm16(Instruction* instr) { // 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 @@ int Decoder::FormatOption(Instruction* instr, const char* format) { } 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::DecodeTypeImmediate(Instruction* instr) { 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 @@ int Decoder::InstructionDecode(byte* instr_ptr) { break; } default: { + Format(instr, "UNSUPPORTED"); UNSUPPORTED_MIPS(); } } diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h index 798ef23..2c83893 100644 --- a/src/mips/frames-mips.h +++ b/src/mips/frames-mips.h @@ -87,7 +87,6 @@ static const RegList kCalleeSavedFPU = 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. diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc index 7628237..17c1897 100644 --- a/src/mips/simulator-mips.cc +++ b/src/mips/simulator-mips.cc @@ -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 @@ int32_t Simulator::get_pc() const { 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(instr)); MipsDebugger dbg(this); dbg.Debug(); } @@ -1234,6 +1237,8 @@ int Simulator::ReadW(int32_t addr, Instruction* instr) { 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(instr)); MipsDebugger dbg(this); dbg.Debug(); } -- 2.7.4