Commit aa00dbdc authored by danno@chromium.org's avatar danno@chromium.org

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 <plind44@gmail.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9259 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e645597a
...@@ -83,6 +83,14 @@ bool Operand::is_reg() const { ...@@ -83,6 +83,14 @@ bool Operand::is_reg() const {
// RelocInfo. // RelocInfo.
void RelocInfo::apply(intptr_t delta) { 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_)) { if (IsInternalReference(rmode_)) {
// Absolute code pointer inside code object moves with the code object. // Absolute code pointer inside code object moves with the code object.
byte* p = reinterpret_cast<byte*>(pc_); byte* p = reinterpret_cast<byte*>(pc_);
...@@ -218,8 +226,9 @@ bool RelocInfo::IsPatchedReturnSequence() { ...@@ -218,8 +226,9 @@ bool RelocInfo::IsPatchedReturnSequence() {
Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize); Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
bool patched_return = ((instr0 & kOpcodeMask) == LUI && bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
(instr1 & kOpcodeMask) == ORI && (instr1 & kOpcodeMask) == ORI &&
(instr2 & kOpcodeMask) == SPECIAL && ((instr2 & kOpcodeMask) == JAL ||
(instr2 & kFunctionFieldMask) == JALR); ((instr2 & kOpcodeMask) == SPECIAL &&
(instr2 & kFunctionFieldMask) == JALR)));
return patched_return; return patched_return;
} }
......
This diff is collapsed.
...@@ -168,24 +168,36 @@ Register ToRegister(int num); ...@@ -168,24 +168,36 @@ Register ToRegister(int num);
// Coprocessor register. // Coprocessor register.
struct FPURegister { struct FPURegister {
static const int kNumRegisters = v8::internal::kNumFPURegisters; static const int kNumRegisters = v8::internal::kNumFPURegisters;
// f0 has been excluded from allocation. This is following ia32
// where xmm0 is excluded. // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
static const int kNumAllocatableRegisters = 15; // 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) { static int ToAllocationIndex(FPURegister reg) {
ASSERT(reg.code() != 0);
ASSERT(reg.code() % 2 == 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) { static FPURegister FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters); ASSERT(index >= 0 && index < kNumAllocatableRegisters);
return from_code((index + 1) * 2); return from_code(index * 2);
} }
static const char* AllocationIndexToString(int index) { static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters); ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = { const char* const names[] = {
"f0",
"f2", "f2",
"f4", "f4",
"f6", "f6",
...@@ -198,9 +210,7 @@ struct FPURegister { ...@@ -198,9 +210,7 @@ struct FPURegister {
"f20", "f20",
"f22", "f22",
"f24", "f24",
"f26", "f26"
"f28",
"f30"
}; };
return names[index]; return names[index];
} }
...@@ -212,6 +222,23 @@ struct FPURegister { ...@@ -212,6 +222,23 @@ struct FPURegister {
bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; } bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; }
bool is(FPURegister creg) const { return code_ == creg.code_; } 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 { int code() const {
ASSERT(is_valid()); ASSERT(is_valid());
return code_; return code_;
...@@ -228,9 +255,19 @@ struct FPURegister { ...@@ -228,9 +255,19 @@ struct FPURegister {
int code_; 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 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 f0 = { 0 }; // Return value in hard float mode.
const FPURegister f1 = { 1 }; const FPURegister f1 = { 1 };
...@@ -265,6 +302,8 @@ const FPURegister f29 = { 29 }; ...@@ -265,6 +302,8 @@ const FPURegister f29 = { 29 };
const FPURegister f30 = { 30 }; const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 }; const FPURegister f31 = { 31 };
const FPURegister kDoubleRegZero = f28;
// FPU (coprocessor 1) control registers. // FPU (coprocessor 1) control registers.
// Currently only FCSR (#31) is implemented. // Currently only FCSR (#31) is implemented.
struct FPUControlRegister { struct FPUControlRegister {
...@@ -331,6 +370,10 @@ class MemOperand : public Operand { ...@@ -331,6 +370,10 @@ class MemOperand : public Operand {
explicit MemOperand(Register rn, int32_t offset = 0); explicit MemOperand(Register rn, int32_t offset = 0);
int32_t offset() const { return offset_; } int32_t offset() const { return offset_; }
bool OffsetIsInt16Encodable() const {
return is_int16(offset_);
}
private: private:
int32_t offset_; int32_t offset_;
...@@ -504,6 +547,8 @@ class Assembler : public AssemblerBase { ...@@ -504,6 +547,8 @@ class Assembler : public AssemblerBase {
static Address target_address_at(Address pc); static Address target_address_at(Address pc);
static void set_target_address_at(Address pc, Address target); 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 sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code. // This is for calls and branches within generated code.
inline static void set_target_at(Address instruction_payload, inline static void set_target_at(Address instruction_payload,
...@@ -534,9 +579,13 @@ class Assembler : public AssemblerBase { ...@@ -534,9 +579,13 @@ class Assembler : public AssemblerBase {
static const int kExternalTargetSize = 0 * kInstrSize; static const int kExternalTargetSize = 0 * kInstrSize;
// Number of consecutive instructions used to store 32bit constant. // Number of consecutive instructions used to store 32bit constant.
// Used in RelocInfo::target_address_address() function to tell serializer // Before jump-optimizations, this constant was used in
// address of the instruction that follows LUI/ORI instruction pair. // RelocInfo::target_address_address() function to tell serializer address of
static const int kInstructionsFor32BitConstant = 2; // 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 // Distance between the instruction referring to the address of the call
// target and the return address. // target and the return address.
...@@ -623,6 +672,8 @@ class Assembler : public AssemblerBase { ...@@ -623,6 +672,8 @@ class Assembler : public AssemblerBase {
void jal(int32_t target); void jal(int32_t target);
void jalr(Register rs, Register rd = ra); void jalr(Register rs, Register rd = ra);
void jr(Register target); 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--------- //-------Data-processing-instructions---------
...@@ -892,6 +943,10 @@ class Assembler : public AssemblerBase { ...@@ -892,6 +943,10 @@ class Assembler : public AssemblerBase {
static bool IsLui(Instr instr); static bool IsLui(Instr instr);
static bool IsOri(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 IsNop(Instr instr, unsigned int type);
static bool IsPop(Instr instr); static bool IsPop(Instr instr);
static bool IsPush(Instr instr); static bool IsPush(Instr instr);
...@@ -976,6 +1031,8 @@ class Assembler : public AssemblerBase { ...@@ -976,6 +1031,8 @@ class Assembler : public AssemblerBase {
return internal_trampoline_exception_; return internal_trampoline_exception_;
} }
void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);
bool is_trampoline_emitted() const { bool is_trampoline_emitted() const {
return trampoline_emitted_; return trampoline_emitted_;
} }
......
...@@ -191,6 +191,7 @@ bool Instruction::IsLinkingInstruction() const { ...@@ -191,6 +191,7 @@ bool Instruction::IsLinkingInstruction() const {
const int op = OpcodeFieldRaw(); const int op = OpcodeFieldRaw();
switch (op) { switch (op) {
case JAL: case JAL:
return true;
case REGIMM: case REGIMM:
switch (RtFieldRaw()) { switch (RtFieldRaw()) {
case BGEZAL: case BGEZAL:
...@@ -272,7 +273,7 @@ Instruction::Type Instruction::InstructionType() const { ...@@ -272,7 +273,7 @@ Instruction::Type Instruction::InstructionType() const {
case MOVCI: case MOVCI:
return kRegisterType; return kRegisterType;
default: default:
UNREACHABLE(); return kUnsupported;
}; };
break; break;
case SPECIAL2: case SPECIAL2:
...@@ -281,7 +282,7 @@ Instruction::Type Instruction::InstructionType() const { ...@@ -281,7 +282,7 @@ Instruction::Type Instruction::InstructionType() const {
case CLZ: case CLZ:
return kRegisterType; return kRegisterType;
default: default:
UNREACHABLE(); return kUnsupported;
}; };
break; break;
case SPECIAL3: case SPECIAL3:
...@@ -290,7 +291,7 @@ Instruction::Type Instruction::InstructionType() const { ...@@ -290,7 +291,7 @@ Instruction::Type Instruction::InstructionType() const {
case EXT: case EXT:
return kRegisterType; return kRegisterType;
default: default:
UNREACHABLE(); return kUnsupported;
}; };
break; break;
case COP1: // Coprocessor instructions. case COP1: // Coprocessor instructions.
...@@ -341,7 +342,7 @@ Instruction::Type Instruction::InstructionType() const { ...@@ -341,7 +342,7 @@ Instruction::Type Instruction::InstructionType() const {
case JAL: case JAL:
return kJumpType; return kJumpType;
default: default:
UNREACHABLE(); return kUnsupported;
}; };
return kUnsupported; return kUnsupported;
} }
......
...@@ -204,6 +204,10 @@ static const int kImm26Bits = 26; ...@@ -204,6 +204,10 @@ static const int kImm26Bits = 26;
static const int kImm28Shift = 0; static const int kImm28Shift = 0;
static const int kImm28Bits = 28; 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 kFsShift = 11;
static const int kFsBits = 5; static const int kFsBits = 5;
static const int kFtShift = 16; static const int kFtShift = 16;
...@@ -233,7 +237,7 @@ static const int kFunctionFieldMask = ...@@ -233,7 +237,7 @@ static const int kFunctionFieldMask =
static const int kHiMask = 0xffff << 16; static const int kHiMask = 0xffff << 16;
static const int kLoMask = 0xffff; static const int kLoMask = 0xffff;
static const int kSignMask = 0x80000000; static const int kSignMask = 0x80000000;
static const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;
// ----- MIPS Opcodes and Function Fields. // ----- MIPS Opcodes and Function Fields.
// We use this presentation to stay close to the table representation in // We use this presentation to stay close to the table representation in
...@@ -290,12 +294,12 @@ enum Opcode { ...@@ -290,12 +294,12 @@ enum Opcode {
enum SecondaryField { enum SecondaryField {
// SPECIAL Encoding of Function Field. // SPECIAL Encoding of Function Field.
SLL = ((0 << 3) + 0), SLL = ((0 << 3) + 0),
MOVCI = ((0 << 3) + 1),
SRL = ((0 << 3) + 2), SRL = ((0 << 3) + 2),
SRA = ((0 << 3) + 3), SRA = ((0 << 3) + 3),
SLLV = ((0 << 3) + 4), SLLV = ((0 << 3) + 4),
SRLV = ((0 << 3) + 6), SRLV = ((0 << 3) + 6),
SRAV = ((0 << 3) + 7), SRAV = ((0 << 3) + 7),
MOVCI = ((0 << 3) + 1),
JR = ((1 << 3) + 0), JR = ((1 << 3) + 0),
JALR = ((1 << 3) + 1), JALR = ((1 << 3) + 1),
...@@ -498,14 +502,38 @@ inline Condition ReverseCondition(Condition cc) { ...@@ -498,14 +502,38 @@ inline Condition ReverseCondition(Condition cc) {
// ----- Coprocessor conditions. // ----- Coprocessor conditions.
enum FPUCondition { enum FPUCondition {
F, // False. kNoFPUCondition = -1,
UN, // Unordered.
EQ, // Equal. F = 0, // False.
UEQ, // Unordered or Equal. UN = 1, // Unordered.
OLT, // Ordered or Less Than. EQ = 2, // Equal.
ULT, // Unordered or Less Than. UEQ = 3, // Unordered or Equal.
OLE, // Ordered or Less Than or Equal. OLT = 4, // Ordered or Less Than.
ULE // Unordered or Less Than or Equal. 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 { ...@@ -716,7 +744,7 @@ class Instruction {
inline int32_t Imm26Value() const { inline int32_t Imm26Value() const {
ASSERT(InstructionType() == kJumpType); 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. // Say if the instruction should not be used in a branch delay slot.
......
...@@ -112,7 +112,7 @@ class Decoder { ...@@ -112,7 +112,7 @@ class Decoder {
void PrintUImm16(Instruction* instr); void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr); void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr); void PrintXImm16(Instruction* instr);
void PrintImm26(Instruction* instr); void PrintXImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions. void PrintCode(Instruction* instr); // For break and trap instructions.
// Printing of instruction name. // Printing of instruction name.
void PrintInstructionName(Instruction* instr); void PrintInstructionName(Instruction* instr);
...@@ -273,9 +273,9 @@ void Decoder::PrintXImm16(Instruction* instr) { ...@@ -273,9 +273,9 @@ void Decoder::PrintXImm16(Instruction* instr) {
// Print 26-bit immediate value. // Print 26-bit immediate value.
void Decoder::PrintImm26(Instruction* instr) { void Decoder::PrintXImm26(Instruction* instr) {
int32_t imm = instr->Imm26Value(); uint32_t imm = instr->Imm26Value() << kImmFieldShift;
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); 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) { ...@@ -383,9 +383,9 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
} }
return 6; return 6;
} else { } else {
ASSERT(STRING_STARTS_WITH(format, "imm26")); ASSERT(STRING_STARTS_WITH(format, "imm26x"));
PrintImm26(instr); PrintXImm26(instr);
return 5; return 6;
} }
} }
case 'r': { // 'r: registers. case 'r': { // 'r: registers.
...@@ -926,10 +926,10 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) { ...@@ -926,10 +926,10 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
void Decoder::DecodeTypeJump(Instruction* instr) { void Decoder::DecodeTypeJump(Instruction* instr) {
switch (instr->OpcodeFieldRaw()) { switch (instr->OpcodeFieldRaw()) {
case J: case J:
Format(instr, "j 'imm26"); Format(instr, "j 'imm26x");
break; break;
case JAL: case JAL:
Format(instr, "jal 'imm26"); Format(instr, "jal 'imm26x");
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -958,6 +958,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { ...@@ -958,6 +958,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
break; break;
} }
default: { default: {
Format(instr, "UNSUPPORTED");
UNSUPPORTED_MIPS(); UNSUPPORTED_MIPS();
} }
} }
......
...@@ -87,7 +87,6 @@ static const RegList kCalleeSavedFPU = ...@@ -87,7 +87,6 @@ static const RegList kCalleeSavedFPU =
static const int kNumCalleeSavedFPU = 6; static const int kNumCalleeSavedFPU = 6;
// Number of registers for which space is reserved in safepoints. Must be a // Number of registers for which space is reserved in safepoints. Must be a
// multiple of 8. // multiple of 8.
// TODO(mips): Only 8 registers may actually be sufficient. Revisit.
static const int kNumSafepointRegisters = 24; static const int kNumSafepointRegisters = 24;
// Define the list of registers actually saved at safepoints. // Define the list of registers actually saved at safepoints.
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#if defined(V8_TARGET_ARCH_MIPS) #if defined(V8_TARGET_ARCH_MIPS)
#include "cpu.h"
#include "disasm.h" #include "disasm.h"
#include "assembler.h" #include "assembler.h"
#include "globals.h" // Need the BitCast. #include "globals.h" // Need the BitCast.
...@@ -1215,6 +1216,8 @@ int32_t Simulator::get_pc() const { ...@@ -1215,6 +1216,8 @@ int32_t Simulator::get_pc() const {
int Simulator::ReadW(int32_t addr, Instruction* instr) { int Simulator::ReadW(int32_t addr, Instruction* instr) {
if (addr >=0 && addr < 0x400) { if (addr >=0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger. // 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); MipsDebugger dbg(this);
dbg.Debug(); dbg.Debug();
} }
...@@ -1234,6 +1237,8 @@ int Simulator::ReadW(int32_t addr, Instruction* instr) { ...@@ -1234,6 +1237,8 @@ int Simulator::ReadW(int32_t addr, Instruction* instr) {
void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
if (addr >= 0 && addr < 0x400) { if (addr >= 0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger. // 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); MipsDebugger dbg(this);
dbg.Debug(); dbg.Debug();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment