Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Unified Diff: src/mips64/simulator-mips64.cc

Issue 371923006: Add mips64 port. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebase Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/mips64/simulator-mips64.h ('k') | src/mips64/stub-cache-mips64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/mips64/simulator-mips64.cc
diff --git a/src/mips/simulator-mips.cc b/src/mips64/simulator-mips64.cc
similarity index 73%
copy from src/mips/simulator-mips.cc
copy to src/mips64/simulator-mips64.cc
index 052eaed8272f7224d1fc7830dc92c48770cb108f..86e8b91464eacbd74a54294a7a14fee232673782 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips64/simulator-mips64.cc
@@ -9,13 +9,13 @@
#include "src/v8.h"
-#if V8_TARGET_ARCH_MIPS
+#if V8_TARGET_ARCH_MIPS64
#include "src/assembler.h"
#include "src/disasm.h"
#include "src/globals.h" // Need the BitCast.
-#include "src/mips/constants-mips.h"
-#include "src/mips/simulator-mips.h"
+#include "src/mips64/constants-mips64.h"
+#include "src/mips64/simulator-mips64.h"
// Only build the simulator if not compiling for real MIPS hardware.
@@ -25,7 +25,7 @@ namespace v8 {
namespace internal {
// Utils functions.
-bool HaveSameSign(int32_t a, int32_t b) {
+bool HaveSameSign(int64_t a, int64_t b) {
return ((a ^ b) >= 0);
}
@@ -39,6 +39,25 @@ uint32_t get_fcsr_condition_bit(uint32_t cc) {
}
+static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
+ uint64_t u0, v0, w0;
+ int64_t u1, v1, w1, w2, t;
+
+ u0 = u & 0xffffffffL;
+ u1 = u >> 32;
+ v0 = v & 0xffffffffL;
+ v1 = v >> 32;
+
+ w0 = u0 * v0;
+ t = u1 * v0 + (w0 >> 32);
+ w1 = t & 0xffffffffL;
+ w2 = t >> 32;
+ w1 = u0 * v1 + w1;
+
+ return u1 * v1 + w2 + (w1 >> 32);
+}
+
+
// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent was through
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
@@ -65,12 +84,11 @@ class MipsDebugger {
Simulator* sim_;
- int32_t GetRegisterValue(int regnum);
- int32_t GetFPURegisterValueInt(int regnum);
- int64_t GetFPURegisterValueLong(int regnum);
+ int64_t GetRegisterValue(int regnum);
+ int64_t GetFPURegisterValue(int regnum);
float GetFPURegisterValueFloat(int regnum);
double GetFPURegisterValueDouble(int regnum);
- bool GetValue(const char* desc, int32_t* value);
+ bool GetValue(const char* desc, int64_t* value);
// Set or delete a breakpoint. Returns true if successful.
bool SetBreakpoint(Instruction* breakpc);
@@ -122,7 +140,8 @@ void MipsDebugger::Stop(Instruction* instr) {
instr->SetInstructionBits(kNopInstr);
reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
}
- sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstructionSize);
+ // TODO(yuyin): 2 -> 3?
+ sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstructionSize);
}
@@ -144,13 +163,14 @@ void MipsDebugger::Stop(Instruction* instr) {
sim_->watched_stops_[code].desc = msg;
}
PrintF("Simulator hit %s (%u)\n", msg, code);
- sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
+ // TODO(yuyin): 2 -> 3?
+ sim_->set_pc(sim_->get_pc() + 3 * Instruction::kInstrSize);
Debug();
}
#endif // GENERATED_CODE_COVERAGE
-int32_t MipsDebugger::GetRegisterValue(int regnum) {
+int64_t MipsDebugger::GetRegisterValue(int regnum) {
if (regnum == kNumSimuRegisters) {
return sim_->get_pc();
} else {
@@ -159,7 +179,7 @@ int32_t MipsDebugger::GetRegisterValue(int regnum) {
}
-int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
+int64_t MipsDebugger::GetFPURegisterValue(int regnum) {
if (regnum == kNumFPURegisters) {
return sim_->get_pc();
} else {
@@ -168,15 +188,6 @@ int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
}
-int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
- if (regnum == kNumFPURegisters) {
- return sim_->get_pc();
- } else {
- return sim_->get_fpu_register_long(regnum);
- }
-}
-
-
float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
if (regnum == kNumFPURegisters) {
return sim_->get_pc();
@@ -195,7 +206,7 @@ double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
}
-bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
+bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
int regnum = Registers::Number(desc);
int fpuregnum = FPURegisters::Number(desc);
@@ -203,12 +214,13 @@ bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
*value = GetRegisterValue(regnum);
return true;
} else if (fpuregnum != kInvalidFPURegister) {
- *value = GetFPURegisterValueInt(fpuregnum);
+ *value = GetFPURegisterValue(fpuregnum);
return true;
} else if (strncmp(desc, "0x", 2) == 0) {
- return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
+ return SScanF(desc + 2, "%" SCNx64,
+ reinterpret_cast<uint64_t*>(value)) == 1;
} else {
- return SScanF(desc, "%i", value) == 1;
+ return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
}
return false;
}
@@ -259,33 +271,33 @@ void MipsDebugger::PrintAllRegs() {
PrintF("\n");
// at, v0, a0.
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(1), REG_INFO(2), REG_INFO(4));
// v1, a1.
- PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%34s\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
"", REG_INFO(3), REG_INFO(5));
// a2.
- PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
+ PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(6));
// a3.
- PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
+ PrintF("%34s\t%34s\t%3s: 0x%016lx %14ld\n", "", "", REG_INFO(7));
PrintF("\n");
- // t0-t7, s0-s7
+ // a4-t3, s0-s7
for (int i = 0; i < 8; i++) {
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(8+i), REG_INFO(16+i));
}
PrintF("\n");
// t8, k0, LO.
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(24), REG_INFO(26), REG_INFO(32));
// t9, k1, HI.
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(25), REG_INFO(27), REG_INFO(33));
// sp, fp, gp.
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(29), REG_INFO(30), REG_INFO(28));
// pc.
- PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
+ PrintF("%3s: 0x%016lx %14ld\t%3s: 0x%016lx %14ld\n",
REG_INFO(31), REG_INFO(34));
#undef REG_INFO
@@ -294,31 +306,47 @@ void MipsDebugger::PrintAllRegs() {
void MipsDebugger::PrintAllRegsIncludingFPU() {
-#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
- GetFPURegisterValueInt(n+1), \
- GetFPURegisterValueInt(n), \
- GetFPURegisterValueDouble(n)
+#define FPU_REG_INFO(n) FPURegisters::Name(n), \
+ GetFPURegisterValue(n), \
+ GetFPURegisterValueDouble(n)
PrintAllRegs();
PrintF("\n\n");
// f0, f1, f2, ... f31.
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
+ // TODO(plind): consider printing 2 columns for space efficiency.
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(0) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(1) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(2) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(3) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(4) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(5) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(6) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(7) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(8) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(9) );
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(10));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(11));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(12));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(13));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(14));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(15));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(16));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(17));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(18));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(19));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(20));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(21));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(22));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(23));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(24));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(25));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(26));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(27));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(28));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(29));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(30));
+ PrintF("%3s: 0x%016lx %16.4e\n", FPU_REG_INFO(31));
#undef REG_INFO
#undef FPU_REG_INFO
@@ -357,7 +385,7 @@ void MipsDebugger::Debug() {
v8::internal::EmbeddedVector<char, 256> buffer;
dasm.InstructionDecode(buffer,
reinterpret_cast<byte*>(sim_->get_pc()));
- PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.start());
+ PrintF(" 0x%016lx %s\n", sim_->get_pc(), buffer.start());
last_pc = sim_->get_pc();
}
char* line = ReadLine("sim> ");
@@ -396,8 +424,8 @@ void MipsDebugger::Debug() {
done = true;
} else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
if (argc == 2) {
- int32_t value;
- float fvalue;
+ int64_t value;
+ double dvalue;
if (strcmp(arg1, "all") == 0) {
PrintAllRegs();
} else if (strcmp(arg1, "allf") == 0) {
@@ -408,24 +436,12 @@ void MipsDebugger::Debug() {
if (regnum != kInvalidRegister) {
value = GetRegisterValue(regnum);
- PrintF("%s: 0x%08x %d \n", arg1, value, value);
+ PrintF("%s: 0x%08lx %ld \n", arg1, value, value);
} else if (fpuregnum != kInvalidFPURegister) {
- if (fpuregnum % 2 == 1) {
- value = GetFPURegisterValueInt(fpuregnum);
- fvalue = GetFPURegisterValueFloat(fpuregnum);
- PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
- } else {
- double dfvalue;
- int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
- int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
- dfvalue = GetFPURegisterValueDouble(fpuregnum);
- PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
- FPURegisters::Name(fpuregnum+1),
- FPURegisters::Name(fpuregnum),
- lvalue1,
- lvalue2,
- dfvalue);
- }
+ value = GetFPURegisterValue(fpuregnum);
+ dvalue = GetFPURegisterValueDouble(fpuregnum);
+ PrintF("%3s: 0x%016lx %16.4e\n",
+ FPURegisters::Name(fpuregnum), value, dvalue);
} else {
PrintF("%s unrecognized\n", arg1);
}
@@ -433,14 +449,15 @@ void MipsDebugger::Debug() {
} else {
if (argc == 3) {
if (strcmp(arg2, "single") == 0) {
- int32_t value;
+ int64_t value;
float fvalue;
int fpuregnum = FPURegisters::Number(arg1);
if (fpuregnum != kInvalidFPURegister) {
- value = GetFPURegisterValueInt(fpuregnum);
+ value = GetFPURegisterValue(fpuregnum);
+ value &= 0xffffffffUL;
fvalue = GetFPURegisterValueFloat(fpuregnum);
- PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
+ PrintF("%s: 0x%08lx %11.4e\n", arg1, value, fvalue);
} else {
PrintF("%s unrecognized\n", arg1);
}
@@ -454,7 +471,7 @@ void MipsDebugger::Debug() {
} else if ((strcmp(cmd, "po") == 0)
|| (strcmp(cmd, "printobject") == 0)) {
if (argc == 2) {
- int32_t value;
+ int64_t value;
OFStream os(stdout);
if (GetValue(arg1, &value)) {
Object* obj = reinterpret_cast<Object*>(value);
@@ -472,23 +489,23 @@ void MipsDebugger::Debug() {
PrintF("printobject <value>\n");
}
} else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
- int32_t* cur = NULL;
- int32_t* end = NULL;
+ int64_t* cur = NULL;
+ int64_t* end = NULL;
int next_arg = 1;
if (strcmp(cmd, "stack") == 0) {
- cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
+ cur = reinterpret_cast<int64_t*>(sim_->get_register(Simulator::sp));
} else { // Command "mem".
- int32_t value;
+ int64_t value;
if (!GetValue(arg1, &value)) {
PrintF("%s unrecognized\n", arg1);
continue;
}
- cur = reinterpret_cast<int32_t*>(value);
+ cur = reinterpret_cast<int64_t*>(value);
next_arg++;
}
- int32_t words;
+ int64_t words;
if (argc == next_arg) {
words = 10;
} else {
@@ -499,15 +516,15 @@ void MipsDebugger::Debug() {
end = cur + words;
while (cur < end) {
- PrintF(" 0x%08x: 0x%08x %10d",
+ PrintF(" 0x%012lx: 0x%016lx %14ld",
reinterpret_cast<intptr_t>(cur), *cur, *cur);
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
- int value = *cur;
+ int64_t value = *cur;
Heap* current_heap = v8::internal::Isolate::Current()->heap();
if (((value & 1) == 0) || current_heap->Contains(obj)) {
PrintF(" (");
if ((value & 1) == 0) {
- PrintF("smi %d", value / 2);
+ PrintF("smi %d", static_cast<int>(value >> 32));
} else {
obj->ShortPrint();
}
@@ -535,7 +552,7 @@ void MipsDebugger::Debug() {
int regnum = Registers::Number(arg1);
if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
// The argument is an address or a register name.
- int32_t value;
+ int64_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte*>(value);
// Disassemble 10 instructions at <arg1>.
@@ -543,7 +560,7 @@ void MipsDebugger::Debug() {
}
} else {
// The argument is the number of instructions.
- int32_t value;
+ int64_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte*>(sim_->get_pc());
// Disassemble <arg1> instructions.
@@ -551,8 +568,8 @@ void MipsDebugger::Debug() {
}
}
} else {
- int32_t value1;
- int32_t value2;
+ int64_t value1;
+ int64_t value2;
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
cur = reinterpret_cast<byte*>(value1);
end = cur + (value2 * Instruction::kInstrSize);
@@ -561,7 +578,7 @@ void MipsDebugger::Debug() {
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n",
+ PrintF(" 0x%08lx %s\n",
reinterpret_cast<intptr_t>(cur), buffer.start());
cur += Instruction::kInstrSize;
}
@@ -571,7 +588,7 @@ void MipsDebugger::Debug() {
PrintF("regaining control from gdb\n");
} else if (strcmp(cmd, "break") == 0) {
if (argc == 2) {
- int32_t value;
+ int64_t value;
if (GetValue(arg1, &value)) {
if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
PrintF("setting breakpoint failed\n");
@@ -589,7 +606,7 @@ void MipsDebugger::Debug() {
} else if (strcmp(cmd, "flags") == 0) {
PrintF("No flags on MIPS !\n");
} else if (strcmp(cmd, "stop") == 0) {
- int32_t value;
+ int64_t value;
intptr_t stop_pc = sim_->get_pc() -
2 * Instruction::kInstrSize;
Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
@@ -666,15 +683,15 @@ void MipsDebugger::Debug() {
cur = reinterpret_cast<byte*>(sim_->get_pc());
end = cur + (10 * Instruction::kInstrSize);
} else if (argc == 2) {
- int32_t value;
+ int64_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte*>(value);
// no length parameter passed, assume 10 instructions
end = cur + (10 * Instruction::kInstrSize);
}
} else {
- int32_t value1;
- int32_t value2;
+ int64_t value1;
+ int64_t value2;
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
cur = reinterpret_cast<byte*>(value1);
end = cur + (value2 * Instruction::kInstrSize);
@@ -683,7 +700,7 @@ void MipsDebugger::Debug() {
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n",
+ PrintF(" 0x%08lx %s\n",
reinterpret_cast<intptr_t>(cur), buffer.start());
cur += Instruction::kInstrSize;
}
@@ -780,8 +797,8 @@ void Simulator::set_last_debugger_input(char* input) {
void Simulator::FlushICache(v8::internal::HashMap* i_cache,
void* start_addr,
size_t size) {
- intptr_t start = reinterpret_cast<intptr_t>(start_addr);
- int intra_line = (start & CachePage::kLineMask);
+ int64_t start = reinterpret_cast<int64_t>(start_addr);
+ int64_t intra_line = (start & CachePage::kLineMask);
start -= intra_line;
size += intra_line;
size = ((size - 1) | CachePage::kLineMask) + 1;
@@ -791,7 +808,7 @@ void Simulator::FlushICache(v8::internal::HashMap* i_cache,
FlushOnePage(i_cache, start, bytes_to_flush);
start += bytes_to_flush;
size -= bytes_to_flush;
- ASSERT_EQ(0, start & CachePage::kPageMask);
+ ASSERT_EQ((uint64_t)0, start & CachePage::kPageMask);
offset = 0;
}
if (size != 0) {
@@ -830,7 +847,7 @@ void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
void Simulator::CheckICache(v8::internal::HashMap* i_cache,
Instruction* instr) {
- intptr_t address = reinterpret_cast<intptr_t>(instr);
+ int64_t address = reinterpret_cast<int64_t>(instr);
void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
int offset = (address & CachePage::kPageMask);
@@ -868,6 +885,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
Initialize(isolate);
// Set up simulator support first. Some of this information is needed to
// setup the architecture state.
+ stack_size_ = FLAG_sim_stack_size * KB;
stack_ = reinterpret_cast<char*>(malloc(stack_size_));
pc_modified_ = false;
icount_ = 0;
@@ -888,7 +906,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
// The sp is initialized to point to the bottom (high address) of the
// allocated stack area. To be safe in potential stack underflows we leave
// some buffer below.
- registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
+ registers_[sp] = reinterpret_cast<int64_t>(stack_) + stack_size_ - 64;
// The ra and pc are initialized to a known bad value that will cause an
// access violation if the simulator ever tries to execute it.
registers_[pc] = bad_ra;
@@ -953,7 +971,7 @@ class Redirection {
return reinterpret_cast<Redirection*>(addr_of_redirection);
}
- static void* ReverseRedirection(int32_t reg) {
+ static void* ReverseRedirection(int64_t reg) {
Redirection* redirection = FromSwiInstruction(
reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
return redirection->external_function();
@@ -993,7 +1011,7 @@ Simulator* Simulator::current(Isolate* isolate) {
// Sets the register in the architecture state. It will also deal with updating
// Simulator internal state for special registers such as PC.
-void Simulator::set_register(int reg, int32_t value) {
+void Simulator::set_register(int reg, int64_t value) {
ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
if (reg == pc) {
pc_modified_ = true;
@@ -1006,17 +1024,36 @@ void Simulator::set_register(int reg, int32_t value) {
void Simulator::set_dw_register(int reg, const int* dbl) {
ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
- registers_[reg] = dbl[0];
- registers_[reg + 1] = dbl[1];
+ registers_[reg] = dbl[1];
+ registers_[reg] = registers_[reg] << 32;
+ registers_[reg] += dbl[0];
}
-void Simulator::set_fpu_register(int fpureg, int32_t value) {
+void Simulator::set_fpu_register(int fpureg, int64_t value) {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
FPUregisters_[fpureg] = value;
}
+void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
+ // Set ONLY lower 32-bits, leaving upper bits untouched.
+ // TODO(plind): big endian issue.
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
+ *pword = value;
+}
+
+
+void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
+ // Set ONLY upper 32-bits, leaving lower bits untouched.
+ // TODO(plind): big endian issue.
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
+ *phiword = value;
+}
+
+
void Simulator::set_fpu_register_float(int fpureg, float value) {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
*BitCast<float*>(&FPUregisters_[fpureg]) = value;
@@ -1024,14 +1061,14 @@ void Simulator::set_fpu_register_float(int fpureg, float value) {
void Simulator::set_fpu_register_double(int fpureg, double value) {
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
*BitCast<double*>(&FPUregisters_[fpureg]) = value;
}
// Get the register from the architecture state. This function does handle
// the special case of accessing the PC register.
-int32_t Simulator::get_register(int reg) const {
+int64_t Simulator::get_register(int reg) const {
ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
if (reg == 0)
return 0;
@@ -1041,53 +1078,67 @@ int32_t Simulator::get_register(int reg) const {
double Simulator::get_double_from_register_pair(int reg) {
+ // TODO(plind): bad ABI stuff, refactor or remove.
ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
double dm_val = 0.0;
// Read the bits from the unsigned integer register_[] array
// into the double precision floating point value and return it.
- char buffer[2 * sizeof(registers_[0])];
- memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
- memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+ char buffer[sizeof(registers_[0])];
+ memcpy(buffer, &registers_[reg], sizeof(registers_[0]));
+ memcpy(&dm_val, buffer, sizeof(registers_[0]));
return(dm_val);
}
-int32_t Simulator::get_fpu_register(int fpureg) const {
+int64_t Simulator::get_fpu_register(int fpureg) const {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
return FPUregisters_[fpureg];
}
-int64_t Simulator::get_fpu_register_long(int fpureg) const {
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
- return *BitCast<int64_t*>(
- const_cast<int32_t*>(&FPUregisters_[fpureg]));
+int32_t Simulator::get_fpu_register_word(int fpureg) const {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
+}
+
+
+int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
+}
+
+
+uint32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ return static_cast<uint32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
}
float Simulator::get_fpu_register_float(int fpureg) const {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
return *BitCast<float*>(
- const_cast<int32_t*>(&FPUregisters_[fpureg]));
+ const_cast<int64_t*>(&FPUregisters_[fpureg]));
}
double Simulator::get_fpu_register_double(int fpureg) const {
- ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
- return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ return *BitCast<double*>(&FPUregisters_[fpureg]);
}
// Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
-// from a0-a3 or f12 and f14.
+// from a0-a3 or f12 and f13 (n64), or f14 (O32).
void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
if (!IsMipsSoftFloatABI) {
+ const int fparg2 = (kMipsAbi == kN64) ? 13 : 14;
*x = get_fpu_register_double(12);
- *y = get_fpu_register_double(14);
+ *y = get_fpu_register_double(fparg2);
*z = get_register(a2);
} else {
+ // TODO(plind): bad ABI stuff, refactor or remove.
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
char buffer[sizeof(*x)];
@@ -1114,7 +1165,7 @@ void Simulator::SetFpResult(const double& result) {
set_fpu_register_double(0, result);
} else {
char buffer[2 * sizeof(registers_[0])];
- int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
+ int64_t* reg_buffer = reinterpret_cast<int64_t*>(buffer);
memcpy(buffer, &result, sizeof(buffer));
// Copy result to v0 and v1.
set_register(v0, reg_buffer[0]);
@@ -1142,6 +1193,40 @@ bool Simulator::test_fcsr_bit(uint32_t cc) {
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round_error(double original, double rounded) {
bool ret = false;
+ double max_int32 = std::numeric_limits<int32_t>::max();
+ double min_int32 = std::numeric_limits<int32_t>::min();
+
+ if (!std::isfinite(original) || !std::isfinite(rounded)) {
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
+ ret = true;
+ }
+
+ if (original != rounded) {
+ set_fcsr_bit(kFCSRInexactFlagBit, true);
+ }
+
+ if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
+ set_fcsr_bit(kFCSRUnderflowFlagBit, true);
+ ret = true;
+ }
+
+ if (rounded > max_int32 || rounded < min_int32) {
+ set_fcsr_bit(kFCSROverflowFlagBit, true);
+ // The reference is not really clear but it seems this is required:
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
+ ret = true;
+ }
+
+ return ret;
+}
+
+
+// Sets the rounding error codes in FCSR based on the result of the rounding.
+// Returns true if the operation was invalid.
+bool Simulator::set_fcsr_round64_error(double original, double rounded) {
+ bool ret = false;
+ double max_int64 = std::numeric_limits<int64_t>::max();
+ double min_int64 = std::numeric_limits<int64_t>::min();
if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
@@ -1157,7 +1242,7 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
ret = true;
}
- if (rounded > INT_MAX || rounded < INT_MIN) {
+ if (rounded > max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true);
// The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
@@ -1169,7 +1254,7 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
// Raw access to the PC register.
-void Simulator::set_pc(int32_t value) {
+void Simulator::set_pc(int64_t value) {
pc_modified_ = true;
registers_[pc] = value;
}
@@ -1181,7 +1266,7 @@ bool Simulator::has_bad_pc() const {
// Raw access to the PC register without the special adjustment when reading.
-int32_t Simulator::get_pc() const {
+int64_t Simulator::get_pc() const {
return registers_[pc];
}
@@ -1194,54 +1279,165 @@ int32_t Simulator::get_pc() const {
// executed in the simulator. Since the host is typically IA32 we will not
// get the correct MIPS-like behaviour on unaligned accesses.
-int Simulator::ReadW(int32_t addr, Instruction* instr) {
+// TODO(plind): refactor this messy debug code when we do unaligned access.
+void Simulator::DieOrDebug() {
+ if (1) { // Flag for this was removed.
+ MipsDebugger dbg(this);
+ dbg.Debug();
+ } else {
+ base::OS::Abort();
+ }
+}
+
+
+void Simulator::TraceRegWr(int64_t value) {
+ if (::v8::internal::FLAG_trace_sim) {
+ SNPrintF(trace_buf_, "%016lx", value);
+ }
+}
+
+
+// TODO(plind): consider making icount_ printing a flag option.
+void Simulator::TraceMemRd(int64_t addr, int64_t value) {
+ if (::v8::internal::FLAG_trace_sim) {
+ SNPrintF(trace_buf_, "%016lx <-- [%016lx] (%ld)",
+ value, addr, icount_);
+ }
+}
+
+
+void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
+ if (::v8::internal::FLAG_trace_sim) {
+ switch (t) {
+ case BYTE:
+ SNPrintF(trace_buf_, " %02x --> [%016lx]",
+ static_cast<int8_t>(value), addr);
+ break;
+ case HALF:
+ SNPrintF(trace_buf_, " %04x --> [%016lx]",
+ static_cast<int16_t>(value), addr);
+ break;
+ case WORD:
+ SNPrintF(trace_buf_, " %08x --> [%016lx]",
+ static_cast<int32_t>(value), addr);
+ break;
+ case DWORD:
+ SNPrintF(trace_buf_, "%016lx --> [%016lx] (%ld)",
+ value, addr, icount_);
+ break;
+ }
+ }
+}
+
+
+// TODO(plind): sign-extend and zero-extend not implmented properly
+// on all the ReadXX functions, I don't think re-interpret cast does it.
+int32_t Simulator::ReadW(int64_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",
+ PrintF("Memory read from bad address: 0x%08lx, pc=0x%08lx\n",
addr, reinterpret_cast<intptr_t>(instr));
- MipsDebugger dbg(this);
- dbg.Debug();
+ DieOrDebug();
+ }
+ if ((addr & 0x3) == 0) {
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
+ return *ptr;
+ }
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
+ addr,
+ reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
+ return 0;
+}
+
+
+uint32_t Simulator::ReadWU(int64_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%08lx, pc=0x%08lx\n",
+ addr, reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
+ }
+ if ((addr & 0x3) == 0) {
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
+ return *ptr;
+ }
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
+ addr,
+ reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
+ return 0;
+}
+
+
+void Simulator::WriteW(int64_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%08lx, pc=0x%08lx\n",
+ addr, reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
+ }
+ if ((addr & 0x3) == 0) {
+ TraceMemWr(addr, value, WORD);
+ int* ptr = reinterpret_cast<int*>(addr);
+ *ptr = value;
+ return;
+ }
+ PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
+ addr,
+ reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
+}
+
+
+int64_t Simulator::Read2W(int64_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%08lx, pc=0x%08lx\n",
+ addr, reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
}
if ((addr & kPointerAlignmentMask) == 0) {
- intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+ int64_t* ptr = reinterpret_cast<int64_t*>(addr);
+ TraceMemRd(addr, *ptr);
return *ptr;
}
- PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- MipsDebugger dbg(this);
- dbg.Debug();
+ DieOrDebug();
return 0;
}
-void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
+void Simulator::Write2W(int64_t addr, int64_t 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",
+ PrintF("Memory write to bad address: 0x%08lx, pc=0x%08lx\n",
addr, reinterpret_cast<intptr_t>(instr));
- MipsDebugger dbg(this);
- dbg.Debug();
+ DieOrDebug();
}
if ((addr & kPointerAlignmentMask) == 0) {
- intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+ TraceMemWr(addr, value, DWORD);
+ int64_t* ptr = reinterpret_cast<int64_t*>(addr);
*ptr = value;
return;
}
- PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- MipsDebugger dbg(this);
- dbg.Debug();
+ DieOrDebug();
}
-double Simulator::ReadD(int32_t addr, Instruction* instr) {
+double Simulator::ReadD(int64_t addr, Instruction* instr) {
if ((addr & kDoubleAlignmentMask) == 0) {
double* ptr = reinterpret_cast<double*>(addr);
return *ptr;
}
- PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned (double) read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
base::OS::Abort();
@@ -1249,90 +1445,99 @@ double Simulator::ReadD(int32_t addr, Instruction* instr) {
}
-void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
+void Simulator::WriteD(int64_t addr, double value, Instruction* instr) {
if ((addr & kDoubleAlignmentMask) == 0) {
double* ptr = reinterpret_cast<double*>(addr);
*ptr = value;
return;
}
- PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned (double) write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- base::OS::Abort();
+ DieOrDebug();
}
-uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
+uint16_t Simulator::ReadHU(int64_t addr, Instruction* instr) {
if ((addr & 1) == 0) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
return *ptr;
}
- PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned unsigned halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- base::OS::Abort();
+ DieOrDebug();
return 0;
}
-int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
+int16_t Simulator::ReadH(int64_t addr, Instruction* instr) {
if ((addr & 1) == 0) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
return *ptr;
}
- PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned signed halfword read at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- base::OS::Abort();
+ DieOrDebug();
return 0;
}
-void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
+void Simulator::WriteH(int64_t addr, uint16_t value, Instruction* instr) {
if ((addr & 1) == 0) {
+ TraceMemWr(addr, value, HALF);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
*ptr = value;
return;
}
- PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
- addr,
- reinterpret_cast<intptr_t>(instr));
- base::OS::Abort();
+ PrintF(
+ "Unaligned unsigned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
+ addr,
+ reinterpret_cast<intptr_t>(instr));
+ DieOrDebug();
}
-void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
+void Simulator::WriteH(int64_t addr, int16_t value, Instruction* instr) {
if ((addr & 1) == 0) {
+ TraceMemWr(addr, value, HALF);
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
*ptr = value;
return;
}
- PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
+ PrintF("Unaligned halfword write at 0x%08lx, pc=0x%08" V8PRIxPTR "\n",
addr,
reinterpret_cast<intptr_t>(instr));
- base::OS::Abort();
+ DieOrDebug();
}
-uint32_t Simulator::ReadBU(int32_t addr) {
+uint32_t Simulator::ReadBU(int64_t addr) {
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
return *ptr & 0xff;
}
-int32_t Simulator::ReadB(int32_t addr) {
+int32_t Simulator::ReadB(int64_t addr) {
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
+ TraceMemRd(addr, static_cast<int64_t>(*ptr));
return *ptr;
}
-void Simulator::WriteB(int32_t addr, uint8_t value) {
+void Simulator::WriteB(int64_t addr, uint8_t value) {
+ TraceMemWr(addr, value, BYTE);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
*ptr = value;
}
-void Simulator::WriteB(int32_t addr, int8_t value) {
+void Simulator::WriteB(int64_t addr, int8_t value) {
+ TraceMemWr(addr, value, BYTE);
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
*ptr = value;
}
@@ -1348,7 +1553,7 @@ uintptr_t Simulator::StackLimit() const {
// Unsupported instructions use Format to print an error and stop execution.
void Simulator::Format(Instruction* instr, const char* format) {
- PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
+ PrintF("Simulator found unsupported instruction:\n 0x%08lx: %s\n",
reinterpret_cast<intptr_t>(instr), format);
UNIMPLEMENTED_MIPS();
}
@@ -1360,12 +1565,19 @@ void Simulator::Format(Instruction* instr, const char* format) {
// 64-bit value. With the code below we assume that all runtime calls return
// 64 bits of result. If they don't, the v1 result register contains a bogus
// value, which is fine because it is caller-saved.
-typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
- int32_t arg1,
- int32_t arg2,
- int32_t arg3,
- int32_t arg4,
- int32_t arg5);
+
+struct ObjectPair {
+ Object* x;
+ Object* y;
+};
+
+typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
+ int64_t arg1,
+ int64_t arg2,
+ int64_t arg3,
+ int64_t arg4,
+ int64_t arg5);
+
// These prototypes handle the four types of FP calls.
typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
@@ -1375,13 +1587,13 @@ typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
-typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
-typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
+typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
+typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1);
// This signature supports direct call to accessor getter callback.
-typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
typedef void (*SimulatorRuntimeProfilingGetterCall)(
- int32_t arg0, int32_t arg1, void* arg2);
+ int64_t arg0, int64_t arg1, void* arg2);
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime. They are also used for debugging with simulator.
@@ -1391,20 +1603,24 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// Are "SPECIAL" class opcode, and are distinuished by function.
int32_t func = instr->FunctionFieldRaw();
uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
-
// We first check if we met a call_rt_redirected.
if (instr->InstructionBits() == rtCallRedirInstr) {
Redirection* redirection = Redirection::FromSwiInstruction(instr);
- int32_t arg0 = get_register(a0);
- int32_t arg1 = get_register(a1);
- int32_t arg2 = get_register(a2);
- int32_t arg3 = get_register(a3);
-
- int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
- // Args 4 and 5 are on the stack after the reserved space for args 0..3.
- int32_t arg4 = stack_pointer[4];
- int32_t arg5 = stack_pointer[5];
-
+ int64_t arg0 = get_register(a0);
+ int64_t arg1 = get_register(a1);
+ int64_t arg2 = get_register(a2);
+ int64_t arg3 = get_register(a3);
+ int64_t arg4, arg5;
+
+ if (kMipsAbi == kN64) {
+ arg4 = get_register(a4); // Abi n64 register a4.
+ arg5 = get_register(a5); // Abi n64 register a5.
+ } else { // Abi O32.
+ int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
+ // Args 4 and 5 are on the stack after the reserved space for args 0..3.
+ arg4 = stack_pointer[4];
+ arg5 = stack_pointer[5];
+ }
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
(redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
@@ -1440,7 +1656,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// This is dodgy but it works because the C entry stubs are never moved.
// See comment in codegen-arm.cc and bug 1242173.
- int32_t saved_ra = get_register(ra);
+ int64_t saved_ra = get_register(ra);
intptr_t external =
reinterpret_cast<intptr_t>(redirection->external_function());
@@ -1482,8 +1698,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
SimulatorRuntimeCompareCall target =
reinterpret_cast<SimulatorRuntimeCompareCall>(external);
iresult = target(dval0, dval1);
- set_register(v0, static_cast<int32_t>(iresult));
- set_register(v1, static_cast<int32_t>(iresult >> 32));
+ set_register(v0, static_cast<int64_t>(iresult));
+ // set_register(v1, static_cast<int64_t>(iresult >> 32));
break;
}
case ExternalReference::BUILTIN_FP_FP_CALL: {
@@ -1528,7 +1744,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
}
} else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p args %08x\n",
+ PrintF("Call to host function at %p args %08lx\n",
reinterpret_cast<void*>(external), arg0);
}
SimulatorRuntimeDirectApiCall target =
@@ -1537,7 +1753,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
} else if (
redirection->type() == ExternalReference::PROFILING_API_CALL) {
if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p args %08x %08x\n",
+ PrintF("Call to host function at %p args %08lx %08lx\n",
reinterpret_cast<void*>(external), arg0, arg1);
}
SimulatorRuntimeProfilingApiCall target =
@@ -1546,7 +1762,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
} else if (
redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p args %08x %08x\n",
+ PrintF("Call to host function at %p args %08lx %08lx\n",
reinterpret_cast<void*>(external), arg0, arg1);
}
SimulatorRuntimeDirectGetterCall target =
@@ -1555,7 +1771,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
} else if (
redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p args %08x %08x %08x\n",
+ PrintF("Call to host function at %p args %08lx %08lx %08lx\n",
reinterpret_cast<void*>(external), arg0, arg1, arg2);
}
SimulatorRuntimeProfilingGetterCall target =
@@ -1567,7 +1783,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
if (::v8::internal::FLAG_trace_sim) {
PrintF(
"Call to host function at %p "
- "args %08x, %08x, %08x, %08x, %08x, %08x\n",
+ "args %08lx, %08lx, %08lx, %08lx, %08lx, %08lx\n",
FUNCTION_ADDR(target),
arg0,
arg1,
@@ -1576,12 +1792,15 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
arg4,
arg5);
}
- int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
- set_register(v0, static_cast<int32_t>(result));
- set_register(v1, static_cast<int32_t>(result >> 32));
+ // int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
+ // set_register(v0, static_cast<int32_t>(result));
+ // set_register(v1, static_cast<int32_t>(result >> 32));
+ ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5);
+ set_register(v0, (int64_t)(result.x));
+ set_register(v1, (int64_t)(result.y));
}
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Returned %08lx : %08lx\n", get_register(v1), get_register(v0));
}
set_register(ra, saved_ra);
set_pc(get_register(ra));
@@ -1602,22 +1821,22 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// Stop helper functions.
-bool Simulator::IsWatchpoint(uint32_t code) {
+bool Simulator::IsWatchpoint(uint64_t code) {
return (code <= kMaxWatchpointCode);
}
-void Simulator::PrintWatchpoint(uint32_t code) {
+void Simulator::PrintWatchpoint(uint64_t code) {
MipsDebugger dbg(this);
++break_count_;
- PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
+ PrintF("\n---- break %ld marker: %3d (instr count: %8ld) ----------"
"----------------------------------",
code, break_count_, icount_);
dbg.PrintAllRegs(); // Print registers and continue running.
}
-void Simulator::HandleStop(uint32_t code, Instruction* instr) {
+void Simulator::HandleStop(uint64_t code, Instruction* instr) {
// Stop if it is enabled, otherwise go on jumping over the stop
// and the message address.
if (IsEnabledStop(code)) {
@@ -1636,31 +1855,31 @@ bool Simulator::IsStopInstruction(Instruction* instr) {
}
-bool Simulator::IsEnabledStop(uint32_t code) {
+bool Simulator::IsEnabledStop(uint64_t code) {
ASSERT(code <= kMaxStopCode);
ASSERT(code > kMaxWatchpointCode);
return !(watched_stops_[code].count & kStopDisabledBit);
}
-void Simulator::EnableStop(uint32_t code) {
+void Simulator::EnableStop(uint64_t code) {
if (!IsEnabledStop(code)) {
watched_stops_[code].count &= ~kStopDisabledBit;
}
}
-void Simulator::DisableStop(uint32_t code) {
+void Simulator::DisableStop(uint64_t code) {
if (IsEnabledStop(code)) {
watched_stops_[code].count |= kStopDisabledBit;
}
}
-void Simulator::IncreaseStopCounter(uint32_t code) {
+void Simulator::IncreaseStopCounter(uint64_t code) {
ASSERT(code <= kMaxStopCode);
if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
- PrintF("Stop counter for code %i has overflowed.\n"
+ PrintF("Stop counter for code %ld has overflowed.\n"
"Enabling this code and reseting the counter to 0.\n", code);
watched_stops_[code].count = 0;
EnableStop(code);
@@ -1671,7 +1890,7 @@ void Simulator::IncreaseStopCounter(uint32_t code) {
// Print a stop status.
-void Simulator::PrintStopInfo(uint32_t code) {
+void Simulator::PrintStopInfo(uint64_t code) {
if (code <= kMaxWatchpointCode) {
PrintF("That is a watchpoint, not a stop.\n");
return;
@@ -1684,10 +1903,10 @@ void Simulator::PrintStopInfo(uint32_t code) {
// Don't print the state of unused breakpoints.
if (count != 0) {
if (watched_stops_[code].desc) {
- PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
+ PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i, \t%s\n",
code, code, state, count, watched_stops_[code].desc);
} else {
- PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
+ PrintF("stop %ld - 0x%lx: \t%s, \tcounter = %i\n",
code, code, state, count);
}
}
@@ -1706,26 +1925,28 @@ void Simulator::SignalExceptions() {
// Handle execution based on instruction types.
void Simulator::ConfigureTypeRegister(Instruction* instr,
- int32_t* alu_out,
+ int64_t* alu_out,
int64_t* i64hilo,
uint64_t* u64hilo,
- int32_t* next_pc,
- int32_t* return_addr_reg,
- bool* do_interrupt) {
+ int64_t* next_pc,
+ int64_t* return_addr_reg,
+ bool* do_interrupt,
+ int64_t* i128resultH,
+ int64_t* i128resultL) {
// Every local variable declared here needs to be const.
// This is to make sure that changed values are sent back to
// DecodeTypeRegister correctly.
// Instruction fields.
const Opcode op = instr->OpcodeFieldRaw();
- const int32_t rs_reg = instr->RsValue();
- const int32_t rs = get_register(rs_reg);
- const uint32_t rs_u = static_cast<uint32_t>(rs);
- const int32_t rt_reg = instr->RtValue();
- const int32_t rt = get_register(rt_reg);
- const uint32_t rt_u = static_cast<uint32_t>(rt);
- const int32_t rd_reg = instr->RdValue();
- const uint32_t sa = instr->SaValue();
+ const int64_t rs_reg = instr->RsValue();
+ const int64_t rs = get_register(rs_reg);
+ const uint64_t rs_u = static_cast<uint64_t>(rs);
+ const int64_t rt_reg = instr->RtValue();
+ const int64_t rt = get_register(rt_reg);
+ const uint64_t rt_u = static_cast<uint64_t>(rt);
+ const int64_t rd_reg = instr->RdValue();
+ const uint64_t sa = instr->SaValue();
const int32_t fs_reg = instr->FsValue();
@@ -1743,13 +1964,17 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
*alu_out = FCSR_;
break;
case MFC1:
+ *alu_out = static_cast<int64_t>(get_fpu_register_word(fs_reg));
+ break;
+ case DMFC1:
*alu_out = get_fpu_register(fs_reg);
break;
case MFHC1:
- UNIMPLEMENTED_MIPS();
+ *alu_out = get_fpu_register_hi_word(fs_reg);
break;
case CTC1:
case MTC1:
+ case DMTC1:
case MTHC1:
// Do the store in the execution step.
break;
@@ -1774,30 +1999,64 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
*return_addr_reg = instr->RdValue();
break;
case SLL:
+ *alu_out = (int32_t)rt << sa;
+ break;
+ case DSLL:
*alu_out = rt << sa;
break;
+ case DSLL32:
+ *alu_out = rt << sa << 32;
+ break;
case SRL:
if (rs_reg == 0) {
// Regular logical right shift of a word by a fixed number of
// bits instruction. RS field is always equal to 0.
- *alu_out = rt_u >> sa;
+ *alu_out = (uint32_t)rt_u >> sa;
} else {
// Logical right-rotate of a word by a fixed number of bits. This
// is special case of SRL instruction, added in MIPS32 Release 2.
// RS field is equal to 00001.
- *alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
+ *alu_out = ((uint32_t)rt_u >> sa) | ((uint32_t)rt_u << (32 - sa));
}
break;
+ case DSRL:
+ *alu_out = rt_u >> sa;
+ break;
+ case DSRL32:
+ *alu_out = rt_u >> sa >> 32;
+ break;
case SRA:
+ *alu_out = (int32_t)rt >> sa;
+ break;
+ case DSRA:
*alu_out = rt >> sa;
break;
+ case DSRA32:
+ *alu_out = rt >> sa >> 32;
+ break;
case SLLV:
+ *alu_out = (int32_t)rt << rs;
+ break;
+ case DSLLV:
*alu_out = rt << rs;
break;
case SRLV:
if (sa == 0) {
// Regular logical right-shift of a word by a variable number of
// bits instruction. SA field is always equal to 0.
+ *alu_out = (uint32_t)rt_u >> rs;
+ } else {
+ // Logical right-rotate of a word by a variable number of bits.
+ // This is special case od SRLV instruction, added in MIPS32
+ // Release 2. SA field is equal to 00001.
+ *alu_out =
+ ((uint32_t)rt_u >> rs_u) | ((uint32_t)rt_u << (32 - rs_u));
+ }
+ break;
+ case DSRLV:
+ if (sa == 0) {
+ // Regular logical right-shift of a word by a variable number of
+ // bits instruction. SA field is always equal to 0.
*alu_out = rt_u >> rs;
} else {
// Logical right-rotate of a word by a variable number of bits.
@@ -1807,6 +2066,9 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
}
break;
case SRAV:
+ *alu_out = (int32_t)rt >> rs;
+ break;
+ case DSRAV:
*alu_out = rt >> rs;
break;
case MFHI:
@@ -1816,12 +2078,25 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
*alu_out = get_register(LO);
break;
case MULT:
- *i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
+ // TODO(plind) - Unify MULT/DMULT with single set of 64-bit HI/Lo
+ // regs.
+ // TODO(plind) - make the 32-bit MULT ops conform to spec regarding
+ // checking of 32-bit input values, and un-define operations of HW.
+ *i64hilo = static_cast<int64_t>((int32_t)rs) *
+ static_cast<int64_t>((int32_t)rt);
break;
case MULTU:
*u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
break;
+ case DMULT:
+ *i128resultH = MultiplyHighSigned(rs, rt);
+ *i128resultL = rs * rt;
+ break;
+ case DMULTU:
+ UNIMPLEMENTED_MIPS();
+ break;
case ADD:
+ case DADD:
if (HaveSameSign(rs, rt)) {
if (rs > 0) {
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - rt);
@@ -1831,10 +2106,17 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
}
*alu_out = rs + rt;
break;
- case ADDU:
+ case ADDU: {
+ int32_t alu32_out = rs + rt;
+ // Sign-extend result of 32bit operation into 64bit register.
+ *alu_out = static_cast<int64_t>(alu32_out);
+ }
+ break;
+ case DADDU:
*alu_out = rs + rt;
break;
case SUB:
+ case DSUB:
if (!HaveSameSign(rs, rt)) {
if (rs > 0) {
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue + rt);
@@ -1844,7 +2126,13 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
}
*alu_out = rs - rt;
break;
- case SUBU:
+ case SUBU: {
+ int32_t alu32_out = rs - rt;
+ // Sign-extend result of 32bit operation into 64bit register.
+ *alu_out = static_cast<int64_t>(alu32_out);
+ }
+ break;
+ case DSUBU:
*alu_out = rs - rt;
break;
case AND:
@@ -1867,6 +2155,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
break;
// Break and trap instructions.
case BREAK:
+
*do_interrupt = true;
break;
case TGE:
@@ -1894,6 +2183,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
break;
case DIV:
case DIVU:
+ case DDIV:
+ case DDIVU:
// div and divu never raise exceptions.
break;
default:
@@ -1903,7 +2194,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
case SPECIAL2:
switch (instr->FunctionFieldRaw()) {
case MUL:
- *alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
+ // Only the lower 32 bits are kept.
+ *alu_out = (int32_t)rs_u * (int32_t)rt_u;
break;
case CLZ:
// MIPS32 spec: If no bits were set in GPR rs, the result written to
@@ -1951,35 +2243,38 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
void Simulator::DecodeTypeRegister(Instruction* instr) {
// Instruction fields.
const Opcode op = instr->OpcodeFieldRaw();
- const int32_t rs_reg = instr->RsValue();
- const int32_t rs = get_register(rs_reg);
- const uint32_t rs_u = static_cast<uint32_t>(rs);
- const int32_t rt_reg = instr->RtValue();
- const int32_t rt = get_register(rt_reg);
- const uint32_t rt_u = static_cast<uint32_t>(rt);
- const int32_t rd_reg = instr->RdValue();
+ const int64_t rs_reg = instr->RsValue();
+ const int64_t rs = get_register(rs_reg);
+ const uint64_t rs_u = static_cast<uint32_t>(rs);
+ const int64_t rt_reg = instr->RtValue();
+ const int64_t rt = get_register(rt_reg);
+ const uint64_t rt_u = static_cast<uint32_t>(rt);
+ const int64_t rd_reg = instr->RdValue();
const int32_t fr_reg = instr->FrValue();
const int32_t fs_reg = instr->FsValue();
const int32_t ft_reg = instr->FtValue();
- const int32_t fd_reg = instr->FdValue();
+ const int64_t fd_reg = instr->FdValue();
int64_t i64hilo = 0;
uint64_t u64hilo = 0;
// ALU output.
// It should not be used as is. Instructions using it should always
// initialize it first.
- int32_t alu_out = 0x12345678;
+ int64_t alu_out = 0x12345678;
// For break and trap instructions.
bool do_interrupt = false;
// For jr and jalr.
// Get current pc.
- int32_t current_pc = get_pc();
+ int64_t current_pc = get_pc();
// Next pc
- int32_t next_pc = 0;
- int32_t return_addr_reg = 31;
+ int64_t next_pc = 0;
+ int64_t return_addr_reg = 31;
+
+ int64_t i128resultH;
+ int64_t i128resultL;
// Set up the variables if needed before executing the instruction.
ConfigureTypeRegister(instr,
@@ -1988,7 +2283,9 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
&u64hilo,
&next_pc,
&return_addr_reg,
- &do_interrupt);
+ &do_interrupt,
+ &i128resultH,
+ &i128resultL);
// ---------- Raise exceptions triggered.
SignalExceptions();
@@ -2002,11 +2299,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
case CFC1:
set_register(rt_reg, alu_out);
- case MFC1:
- set_register(rt_reg, alu_out);
break;
+ case MFC1:
+ case DMFC1:
case MFHC1:
- UNIMPLEMENTED_MIPS();
+ set_register(rt_reg, alu_out);
break;
case CTC1:
// At the moment only FCSR is supported.
@@ -2014,10 +2311,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
FCSR_ = registers_[rt_reg];
break;
case MTC1:
- FPUregisters_[fs_reg] = registers_[rt_reg];
+ // Hardware writes upper 32-bits to zero on mtc1.
+ set_fpu_register_hi_word(fs_reg, 0);
+ set_fpu_register_word(fs_reg, registers_[rt_reg]);
+ break;
+ case DMTC1:
+ set_fpu_register(fs_reg, registers_[rt_reg]);
break;
case MTHC1:
- UNIMPLEMENTED_MIPS();
+ set_fpu_register_hi_word(fs_reg, registers_[rt_reg]);
break;
case S:
float f;
@@ -2104,6 +2406,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
// Rounding modes are not yet supported.
ASSERT((FCSR_ & 3) == 0);
// In rounding mode 0 it should behave like ROUND.
+ // No break.
case ROUND_W_D: // Round double to word (round half to even).
{
double rounded = std::floor(fs + 0.5);
@@ -2113,7 +2416,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
// round to the even one.
result--;
}
- set_fpu_register(fd_reg, result);
+ set_fpu_register_word(fd_reg, result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg, kFPUInvalidResult);
}
@@ -2123,7 +2426,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
{
double rounded = trunc(fs);
int32_t result = static_cast<int32_t>(rounded);
- set_fpu_register(fd_reg, result);
+ set_fpu_register_word(fd_reg, result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg, kFPUInvalidResult);
}
@@ -2133,7 +2436,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
{
double rounded = std::floor(fs);
int32_t result = static_cast<int32_t>(rounded);
- set_fpu_register(fd_reg, result);
+ set_fpu_register_word(fd_reg, result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg, kFPUInvalidResult);
}
@@ -2143,7 +2446,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
{
double rounded = std::ceil(fs);
int32_t result = static_cast<int32_t>(rounded);
- set_fpu_register(fd_reg, result);
+ set_fpu_register_word(fd_reg, result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg, kFPUInvalidResult);
}
@@ -2152,38 +2455,48 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case CVT_S_D: // Convert double to float (single).
set_fpu_register_float(fd_reg, static_cast<float>(fs));
break;
- case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
- double rounded = trunc(fs);
- i64 = static_cast<int64_t>(rounded);
- set_fpu_register(fd_reg, i64 & 0xffffffff);
- set_fpu_register(fd_reg + 1, i64 >> 32);
+ case CVT_L_D: // Mips64r2: Truncate double to 64-bit long-word.
+ // Rounding modes are not yet supported.
+ ASSERT((FCSR_ & 3) == 0);
+ // In rounding mode 0 it should behave like ROUND.
+ // No break.
+ case ROUND_L_D: { // Mips64r2 instruction.
+ // check error cases
+ double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
+ int64_t result = static_cast<int64_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round64_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPU64InvalidResult);
+ }
break;
}
- case TRUNC_L_D: { // Mips32r2 instruction.
+ case TRUNC_L_D: { // Mips64r2 instruction.
double rounded = trunc(fs);
- i64 = static_cast<int64_t>(rounded);
- set_fpu_register(fd_reg, i64 & 0xffffffff);
- set_fpu_register(fd_reg + 1, i64 >> 32);
+ int64_t result = static_cast<int64_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round64_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPU64InvalidResult);
+ }
break;
}
- case ROUND_L_D: { // Mips32r2 instruction.
- double rounded =
- fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
- i64 = static_cast<int64_t>(rounded);
- set_fpu_register(fd_reg, i64 & 0xffffffff);
- set_fpu_register(fd_reg + 1, i64 >> 32);
+ case FLOOR_L_D: { // Mips64r2 instruction.
+ double rounded = floor(fs);
+ int64_t result = static_cast<int64_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round64_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPU64InvalidResult);
+ }
break;
}
- case FLOOR_L_D: // Mips32r2 instruction.
- i64 = static_cast<int64_t>(std::floor(fs));
- set_fpu_register(fd_reg, i64 & 0xffffffff);
- set_fpu_register(fd_reg + 1, i64 >> 32);
- break;
- case CEIL_L_D: // Mips32r2 instruction.
- i64 = static_cast<int64_t>(std::ceil(fs));
- set_fpu_register(fd_reg, i64 & 0xffffffff);
- set_fpu_register(fd_reg + 1, i64 >> 32);
+ case CEIL_L_D: { // Mips64r2 instruction.
+ double rounded = ceil(fs);
+ int64_t result = static_cast<int64_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round64_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPU64InvalidResult);
+ }
break;
+ }
case C_F_D:
UNIMPLEMENTED_MIPS();
break;
@@ -2194,11 +2507,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case W:
switch (instr->FunctionFieldRaw()) {
case CVT_S_W: // Convert word to float (single).
- alu_out = get_fpu_register(fs_reg);
+ alu_out = get_fpu_register_signed_word(fs_reg);
set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
break;
case CVT_D_W: // Convert word to double.
- alu_out = get_fpu_register(fs_reg);
+ alu_out = get_fpu_register_signed_word(fs_reg);
set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
break;
default:
@@ -2208,10 +2521,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case L:
switch (instr->FunctionFieldRaw()) {
case CVT_D_L: // Mips32r2 instruction.
- // Watch the signs here, we want 2 32-bit vals
- // to make a sign-64.
- i64 = static_cast<uint32_t>(get_fpu_register(fs_reg));
- i64 |= static_cast<int64_t>(get_fpu_register(fs_reg + 1)) << 32;
+ i64 = get_fpu_register(fs_reg);
set_fpu_register_double(fd_reg, static_cast<double>(i64));
break;
case CVT_S_L:
@@ -2269,7 +2579,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
set_register(HI, static_cast<int32_t>(u64hilo >> 32));
break;
+ case DMULT:
+ set_register(LO, static_cast<int64_t>(i128resultL));
+ set_register(HI, static_cast<int64_t>(i128resultH));
+ break;
+ case DMULTU:
+ UNIMPLEMENTED_MIPS();
+ break;
case DIV:
+ case DDIV:
// Divide by zero and overflow was not checked in the configuration
// step - div and divu do not raise exceptions. On division by 0
// the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
@@ -2302,7 +2620,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
// Conditional moves.
case MOVN:
- if (rt) set_register(rd_reg, rs);
+ if (rt) {
+ set_register(rd_reg, rs);
+ TraceRegWr(rs);
+ }
break;
case MOVCI: {
uint32_t cc = instr->FBccValue();
@@ -2315,16 +2636,21 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
}
case MOVZ:
- if (!rt) set_register(rd_reg, rs);
+ if (!rt) {
+ set_register(rd_reg, rs);
+ TraceRegWr(rs);
+ }
break;
default: // For other special opcodes we do the default operation.
set_register(rd_reg, alu_out);
+ TraceRegWr(alu_out);
}
break;
case SPECIAL2:
switch (instr->FunctionFieldRaw()) {
case MUL:
set_register(rd_reg, alu_out);
+ TraceRegWr(alu_out);
// HI and LO are UNPREDICTABLE after the operation.
set_register(LO, Unpredictable);
set_register(HI, Unpredictable);
@@ -2338,10 +2664,12 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case INS:
// Ins instr leaves result in Rt, rather than Rd.
set_register(rt_reg, alu_out);
+ TraceRegWr(alu_out);
break;
case EXT:
// Ext instr leaves result in Rt, rather than Rd.
set_register(rt_reg, alu_out);
+ TraceRegWr(alu_out);
break;
default:
UNREACHABLE();
@@ -2352,6 +2680,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
// cases.
default:
set_register(rd_reg, alu_out);
+ TraceRegWr(alu_out);
}
}
@@ -2360,10 +2689,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
- 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);
+ int64_t rs = get_register(instr->RsValue());
+ uint64_t rs_u = static_cast<uint64_t>(rs);
+ int64_t rt_reg = instr->RtValue(); // Destination register.
+ int64_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
@@ -2374,24 +2703,26 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
int32_t se_imm16 = imm16;
// Get current pc.
- int32_t current_pc = get_pc();
+ int64_t current_pc = get_pc();
// Next pc.
- int32_t next_pc = bad_ra;
+ int64_t next_pc = bad_ra;
// Used for conditional branch instructions.
bool do_branch = false;
bool execute_branch_delay_instruction = false;
// Used for arithmetic instructions.
- int32_t alu_out = 0;
+ int64_t alu_out = 0;
// Floating point.
double fp_out = 0.0;
uint32_t cc, cc_value, fcsr_cc;
// Used for memory instructions.
- int32_t addr = 0x0;
+ int64_t addr = 0x0;
// Value to be written in memory.
- uint32_t mem_value = 0x0;
+ uint64_t mem_value = 0x0;
+ // Alignment for 32-bit integers used in LWL, LWR, etc.
+ const int kInt32AlignmentMask = sizeof(uint32_t) - 1;
// ---------- Configuration (and execution for REGIMM).
switch (op) {
@@ -2470,6 +2801,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
// ------------- Arithmetic instructions.
case ADDI:
+ case DADDI:
if (HaveSameSign(rs, se_imm16)) {
if (rs > 0) {
exceptions[kIntegerOverflow] = rs > (Registers::kMaxValue - se_imm16);
@@ -2480,7 +2812,13 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
}
alu_out = rs + se_imm16;
break;
- case ADDIU:
+ case ADDIU: {
+ int32_t alu32_out = rs + se_imm16;
+ // Sign-extend result of 32bit operation into 64bit register.
+ alu_out = static_cast<int64_t>(alu32_out);
+ }
+ break;
+ case DADDIU:
alu_out = rs + se_imm16;
break;
case SLTI:
@@ -2498,8 +2836,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case XORI:
alu_out = rs ^ oe_imm16;
break;
- case LUI:
- alu_out = (oe_imm16 << 16);
+ case LUI: {
+ int32_t alu32_out = (oe_imm16 << 16);
+ // Sign-extend result of 32bit operation into 64bit register.
+ alu_out = static_cast<int64_t>(alu32_out);
+ }
break;
// ------------- Memory instructions.
case LB:
@@ -2512,8 +2853,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
case LWL: {
// al_offset is offset of the effective address within an aligned word.
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
- uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset;
uint32_t mask = (1 << byte_shift * 8) - 1;
addr = rs + se_imm16 - al_offset;
alu_out = ReadW(addr, instr);
@@ -2525,6 +2866,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
alu_out = ReadW(addr, instr);
break;
+ case LWU:
+ addr = rs + se_imm16;
+ alu_out = ReadWU(addr, instr);
+ break;
+ case LD:
+ addr = rs + se_imm16;
+ alu_out = Read2W(addr, instr);
+ break;
case LBU:
addr = rs + se_imm16;
alu_out = ReadBU(addr);
@@ -2535,8 +2884,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
case LWR: {
// al_offset is offset of the effective address within an aligned word.
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
- uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset;
uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
addr = rs + se_imm16 - al_offset;
alu_out = ReadW(addr, instr);
@@ -2551,8 +2900,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
break;
case SWL: {
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
- uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
+ uint8_t byte_shift = kInt32AlignmentMask - al_offset;
uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
addr = rs + se_imm16 - al_offset;
mem_value = ReadW(addr, instr) & mask;
@@ -2560,10 +2909,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
}
case SW:
+ case SD:
addr = rs + se_imm16;
break;
case SWR: {
- uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
+ uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask;
uint32_t mask = (1 << al_offset * 8) - 1;
addr = rs + se_imm16 - al_offset;
mem_value = ReadW(addr, instr);
@@ -2610,7 +2960,9 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
// ------------- Arithmetic instructions.
case ADDI:
+ case DADDI:
case ADDIU:
+ case DADDIU:
case SLTI:
case SLTIU:
case ANDI:
@@ -2618,12 +2970,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case XORI:
case LUI:
set_register(rt_reg, alu_out);
+ TraceRegWr(alu_out);
break;
// ------------- Memory instructions.
case LB:
case LH:
case LWL:
case LW:
+ case LWU:
+ case LD:
case LBU:
case LHU:
case LWR:
@@ -2641,11 +2996,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
case SW:
WriteW(addr, rt, instr);
break;
+ case SD:
+ Write2W(addr, rt, instr);
+ break;
case SWR:
WriteW(addr, mem_value, instr);
break;
case LWC1:
- set_fpu_register(ft_reg, alu_out);
+ set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
+ set_fpu_register_word(ft_reg, static_cast<int32_t>(alu_out));
break;
case LDC1:
set_fpu_register_double(ft_reg, fp_out);
@@ -2711,14 +3070,15 @@ void Simulator::InstructionDecode(Instruction* instr) {
CheckICache(isolate_->simulator_i_cache(), instr);
}
pc_modified_ = false;
+
+ v8::internal::EmbeddedVector<char, 256> buffer;
+
if (::v8::internal::FLAG_trace_sim) {
+ SNPrintF(trace_buf_, " ");
disasm::NameConverter converter;
disasm::Disassembler dasm(converter);
// Use a reasonably large buffer.
- v8::internal::EmbeddedVector<char, 256> buffer;
dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
- PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
- buffer.start());
}
switch (instr->InstructionType()) {
@@ -2734,8 +3094,14 @@ void Simulator::InstructionDecode(Instruction* instr) {
default:
UNSUPPORTED();
}
+
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF(" 0x%08lx %-44s %s\n", reinterpret_cast<intptr_t>(instr),
+ buffer.start(), trace_buf_.start());
+ }
+
if (!pc_modified_) {
- set_register(pc, reinterpret_cast<int32_t>(instr) +
+ set_register(pc, reinterpret_cast<int64_t>(instr) +
Instruction::kInstrSize);
}
}
@@ -2745,7 +3111,7 @@ void Simulator::InstructionDecode(Instruction* instr) {
void Simulator::Execute() {
// Get the PC to simulate. Cannot use the accessor here as we need the
// raw PC value and not the one used as input to arithmetic instructions.
- int program_counter = get_pc();
+ int64_t program_counter = get_pc();
if (::v8::internal::FLAG_stop_sim_at == 0) {
// Fast version of the dispatch loop without checking whether the simulator
// should be stopping at a particular executed instruction.
@@ -2761,7 +3127,7 @@ void Simulator::Execute() {
while (program_counter != end_sim_pc) {
Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
icount_++;
- if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
+ if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) {
MipsDebugger dbg(this);
dbg.Debug();
} else {
@@ -2775,7 +3141,7 @@ void Simulator::Execute() {
void Simulator::CallInternal(byte* entry) {
// Prepare to execute the code at entry.
- set_register(pc, reinterpret_cast<int32_t>(entry));
+ set_register(pc, reinterpret_cast<int64_t>(entry));
// Put down marker for end of simulation. The simulator will stop simulation
// when the PC reaches this value. By saving the "end simulation" value into
// the LR the simulation stops when returning to this call point.
@@ -2784,21 +3150,21 @@ void Simulator::CallInternal(byte* entry) {
// Remember the values of callee-saved registers.
// The code below assumes that r9 is not used as sb (static base) in
// simulator code and therefore is regarded as a callee-saved register.
- int32_t s0_val = get_register(s0);
- int32_t s1_val = get_register(s1);
- int32_t s2_val = get_register(s2);
- int32_t s3_val = get_register(s3);
- int32_t s4_val = get_register(s4);
- int32_t s5_val = get_register(s5);
- int32_t s6_val = get_register(s6);
- int32_t s7_val = get_register(s7);
- int32_t gp_val = get_register(gp);
- int32_t sp_val = get_register(sp);
- int32_t fp_val = get_register(fp);
+ int64_t s0_val = get_register(s0);
+ int64_t s1_val = get_register(s1);
+ int64_t s2_val = get_register(s2);
+ int64_t s3_val = get_register(s3);
+ int64_t s4_val = get_register(s4);
+ int64_t s5_val = get_register(s5);
+ int64_t s6_val = get_register(s6);
+ int64_t s7_val = get_register(s7);
+ int64_t gp_val = get_register(gp);
+ int64_t sp_val = get_register(sp);
+ int64_t fp_val = get_register(fp);
// Set up the callee-saved registers with a known value. To be able to check
// that they are preserved properly across JS execution.
- int32_t callee_saved_value = icount_;
+ int64_t callee_saved_value = icount_;
set_register(s0, callee_saved_value);
set_register(s1, callee_saved_value);
set_register(s2, callee_saved_value);
@@ -2840,30 +3206,44 @@ void Simulator::CallInternal(byte* entry) {
}
-int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+int64_t Simulator::Call(byte* entry, int argument_count, ...) {
+ const int kRegisterPassedArguments = (kMipsAbi == kN64) ? 8 : 4;
va_list parameters;
va_start(parameters, argument_count);
// Set up arguments.
- // First four arguments passed in registers.
+ // First four arguments passed in registers in both ABI's.
ASSERT(argument_count >= 4);
- set_register(a0, va_arg(parameters, int32_t));
- set_register(a1, va_arg(parameters, int32_t));
- set_register(a2, va_arg(parameters, int32_t));
- set_register(a3, va_arg(parameters, int32_t));
+ set_register(a0, va_arg(parameters, int64_t));
+ set_register(a1, va_arg(parameters, int64_t));
+ set_register(a2, va_arg(parameters, int64_t));
+ set_register(a3, va_arg(parameters, int64_t));
+
+ if (kMipsAbi == kN64) {
+ // Up to eight arguments passed in registers in N64 ABI.
+ // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this.
+ if (argument_count >= 5) set_register(a4, va_arg(parameters, int64_t));
+ if (argument_count >= 6) set_register(a5, va_arg(parameters, int64_t));
+ if (argument_count >= 7) set_register(a6, va_arg(parameters, int64_t));
+ if (argument_count >= 8) set_register(a7, va_arg(parameters, int64_t));
+ }
// Remaining arguments passed on stack.
- int original_stack = get_register(sp);
+ int64_t original_stack = get_register(sp);
// Compute position of stack on entry to generated code.
- int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
- - kCArgsSlotsSize);
+ int stack_args_count = (argument_count > kRegisterPassedArguments) ?
+ (argument_count - kRegisterPassedArguments) : 0;
+ int stack_args_size = stack_args_count * sizeof(int64_t) + kCArgsSlotsSize;
+ int64_t entry_stack = original_stack - stack_args_size;
+
if (base::OS::ActivationFrameAlignment() != 0) {
entry_stack &= -base::OS::ActivationFrameAlignment();
}
// Store remaining arguments on stack, from low to high memory.
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
- for (int i = 4; i < argument_count; i++) {
- stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
+ for (int i = kRegisterPassedArguments; i < argument_count; i++) {
+ int stack_index = i - kRegisterPassedArguments + kCArgSlotCount;
+ stack_argument[stack_index] = va_arg(parameters, int64_t);
}
va_end(parameters);
set_register(sp, entry_stack);
@@ -2874,15 +3254,16 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) {
CHECK_EQ(entry_stack, get_register(sp));
set_register(sp, original_stack);
- int32_t result = get_register(v0);
+ int64_t result = get_register(v0);
return result;
}
double Simulator::CallFP(byte* entry, double d0, double d1) {
if (!IsMipsSoftFloatABI) {
+ const FPURegister fparg2 = (kMipsAbi == kN64) ? f13 : f14;
set_fpu_register_double(f12, d0);
- set_fpu_register_double(f14, d1);
+ set_fpu_register_double(fparg2, d1);
} else {
int buffer[2];
ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
@@ -2901,7 +3282,7 @@ double Simulator::CallFP(byte* entry, double d0, double d1) {
uintptr_t Simulator::PushAddress(uintptr_t address) {
- int new_sp = get_register(sp) - sizeof(uintptr_t);
+ int64_t new_sp = get_register(sp) - sizeof(uintptr_t);
uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
*stack_slot = address;
set_register(sp, new_sp);
@@ -2910,7 +3291,7 @@ uintptr_t Simulator::PushAddress(uintptr_t address) {
uintptr_t Simulator::PopAddress() {
- int current_sp = get_register(sp);
+ int64_t current_sp = get_register(sp);
uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
uintptr_t address = *stack_slot;
set_register(sp, current_sp + sizeof(uintptr_t));
@@ -2924,4 +3305,4 @@ uintptr_t Simulator::PopAddress() {
#endif // USE_SIMULATOR
-#endif // V8_TARGET_ARCH_MIPS
+#endif // V8_TARGET_ARCH_MIPS64
« no previous file with comments | « src/mips64/simulator-mips64.h ('k') | src/mips64/stub-cache-mips64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698