blob: 4f725cff54a90d6cc1e768987e79e858c73c25ee [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Andrei Popescu31002712010-02-23 13:46:05 +00004
5// A Disassembler object is used to disassemble a block of code instruction by
6// instruction. The default implementation of the NameConverter object can be
7// overriden to modify register names or to do symbol lookup on addresses.
8//
9// The example below will disassemble a block of code and print it to stdout.
10//
11// NameConverter converter;
12// Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +000013// for (byte* pc = begin; pc < end;) {
Steve Block44f0eee2011-05-26 01:26:41 +010014// v8::internal::EmbeddedVector<char, 256> buffer;
15// byte* prev_pc = pc;
16// pc += d.InstructionDecode(buffer, pc);
Andrei Popescu31002712010-02-23 13:46:05 +000017// printf("%p %08x %s\n",
18// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
19// }
20//
21// The Disassembler class also has a convenience method to disassemble a block
22// of code into a FILE*, meaning that the above functionality could also be
23// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
24
25
26#include <assert.h>
Andrei Popescu31002712010-02-23 13:46:05 +000027#include <stdarg.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028#include <stdio.h>
Andrei Popescu31002712010-02-23 13:46:05 +000029#include <string.h>
Andrei Popescu31002712010-02-23 13:46:05 +000030
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031#include "src/v8.h"
Andrei Popescu31002712010-02-23 13:46:05 +000032
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033#if V8_TARGET_ARCH_MIPS
Leon Clarkef7060e22010-06-03 12:02:55 +010034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035#include "src/base/platform/platform.h"
36#include "src/disasm.h"
37#include "src/macro-assembler.h"
38#include "src/mips/constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000039
Steve Block44f0eee2011-05-26 01:26:41 +010040namespace v8 {
41namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000042
43//------------------------------------------------------------------------------
44
45// Decoder decodes and disassembles instructions into an output buffer.
46// It uses the converter to convert register names and call destinations into
47// more informative description.
48class Decoder {
49 public:
50 Decoder(const disasm::NameConverter& converter,
51 v8::internal::Vector<char> out_buffer)
52 : converter_(converter),
53 out_buffer_(out_buffer),
54 out_buffer_pos_(0) {
55 out_buffer_[out_buffer_pos_] = '\0';
56 }
57
58 ~Decoder() {}
59
60 // Writes one disassembled instruction into 'buffer' (0-terminated).
61 // Returns the length of the disassembled machine instruction in bytes.
Ben Murdoch257744e2011-11-30 15:57:28 +000062 int InstructionDecode(byte* instruction);
Andrei Popescu31002712010-02-23 13:46:05 +000063
64 private:
65 // Bottleneck functions to print into the out_buffer.
66 void PrintChar(const char ch);
67 void Print(const char* str);
68
69 // Printing of common values.
70 void PrintRegister(int reg);
Steve Block44f0eee2011-05-26 01:26:41 +010071 void PrintFPURegister(int freg);
Andrei Popescu31002712010-02-23 13:46:05 +000072 void PrintRs(Instruction* instr);
73 void PrintRt(Instruction* instr);
74 void PrintRd(Instruction* instr);
75 void PrintFs(Instruction* instr);
76 void PrintFt(Instruction* instr);
77 void PrintFd(Instruction* instr);
78 void PrintSa(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +010079 void PrintSd(Instruction* instr);
Ben Murdoch257744e2011-11-30 15:57:28 +000080 void PrintSs1(Instruction* instr);
81 void PrintSs2(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +010082 void PrintBc(Instruction* instr);
83 void PrintCc(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +000084 void PrintFunction(Instruction* instr);
85 void PrintSecondaryField(Instruction* instr);
86 void PrintUImm16(Instruction* instr);
87 void PrintSImm16(Instruction* instr);
88 void PrintXImm16(Instruction* instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 void PrintXImm21(Instruction* instr);
Ben Murdoch589d6972011-11-30 16:04:58 +000090 void PrintXImm26(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +000091 void PrintCode(Instruction* instr); // For break and trap instructions.
92 // Printing of instruction name.
93 void PrintInstructionName(Instruction* instr);
94
95 // Handle formatting of instructions and their options.
96 int FormatRegister(Instruction* instr, const char* option);
Steve Block44f0eee2011-05-26 01:26:41 +010097 int FormatFPURegister(Instruction* instr, const char* option);
Andrei Popescu31002712010-02-23 13:46:05 +000098 int FormatOption(Instruction* instr, const char* option);
99 void Format(Instruction* instr, const char* format);
100 void Unknown(Instruction* instr);
101
102 // Each of these functions decodes one particular instruction type.
103 void DecodeTypeRegister(Instruction* instr);
104 void DecodeTypeImmediate(Instruction* instr);
105 void DecodeTypeJump(Instruction* instr);
106
107 const disasm::NameConverter& converter_;
108 v8::internal::Vector<char> out_buffer_;
109 int out_buffer_pos_;
110
111 DISALLOW_COPY_AND_ASSIGN(Decoder);
112};
113
114
115// Support for assertions in the Decoder formatting functions.
116#define STRING_STARTS_WITH(string, compare_string) \
117 (strncmp(string, compare_string, strlen(compare_string)) == 0)
118
119
120// Append the ch to the output buffer.
121void Decoder::PrintChar(const char ch) {
122 out_buffer_[out_buffer_pos_++] = ch;
123}
124
125
126// Append the str to the output buffer.
127void Decoder::Print(const char* str) {
128 char cur = *str++;
129 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
130 PrintChar(cur);
131 cur = *str++;
132 }
133 out_buffer_[out_buffer_pos_] = 0;
134}
135
136
137// Print the register name according to the active name converter.
138void Decoder::PrintRegister(int reg) {
139 Print(converter_.NameOfCPURegister(reg));
140}
141
142
143void Decoder::PrintRs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100144 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000145 PrintRegister(reg);
146}
147
148
149void Decoder::PrintRt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100150 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000151 PrintRegister(reg);
152}
153
154
155void Decoder::PrintRd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100156 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000157 PrintRegister(reg);
158}
159
160
Steve Block44f0eee2011-05-26 01:26:41 +0100161// Print the FPUregister name according to the active name converter.
162void Decoder::PrintFPURegister(int freg) {
163 Print(converter_.NameOfXMMRegister(freg));
Andrei Popescu31002712010-02-23 13:46:05 +0000164}
165
166
167void Decoder::PrintFs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100168 int freg = instr->RsValue();
169 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000170}
171
172
173void Decoder::PrintFt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100174 int freg = instr->RtValue();
175 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000176}
177
178
179void Decoder::PrintFd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100180 int freg = instr->RdValue();
181 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000182}
183
184
185// Print the integer value of the sa field.
186void Decoder::PrintSa(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100187 int sa = instr->SaValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
Steve Block44f0eee2011-05-26 01:26:41 +0100189}
190
191
Ben Murdoch257744e2011-11-30 15:57:28 +0000192// Print the integer value of the rd field, when it is not used as reg.
Steve Block44f0eee2011-05-26 01:26:41 +0100193void Decoder::PrintSd(Instruction* instr) {
194 int sd = instr->RdValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
Steve Block44f0eee2011-05-26 01:26:41 +0100196}
197
198
Ben Murdoch257744e2011-11-30 15:57:28 +0000199// Print the integer value of the rd field, when used as 'ext' size.
200void Decoder::PrintSs1(Instruction* instr) {
201 int ss = instr->RdValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000203}
204
205
206// Print the integer value of the rd field, when used as 'ins' size.
207void Decoder::PrintSs2(Instruction* instr) {
208 int ss = instr->RdValue();
209 int pos = instr->SaValue();
210 out_buffer_pos_ +=
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000212}
213
214
Steve Block44f0eee2011-05-26 01:26:41 +0100215// Print the integer value of the cc field for the bc1t/f instructions.
216void Decoder::PrintBc(Instruction* instr) {
217 int cc = instr->FBccValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
Steve Block44f0eee2011-05-26 01:26:41 +0100219}
220
221
222// Print the integer value of the cc field for the FP compare instructions.
223void Decoder::PrintCc(Instruction* instr) {
224 int cc = instr->FCccValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
Andrei Popescu31002712010-02-23 13:46:05 +0000226}
227
228
229// Print 16-bit unsigned immediate value.
230void Decoder::PrintUImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100231 int32_t imm = instr->Imm16Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000233}
234
235
236// Print 16-bit signed immediate value.
237void Decoder::PrintSImm16(Instruction* instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000238 int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000240}
241
242
243// Print 16-bit hexa immediate value.
244void Decoder::PrintXImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100245 int32_t imm = instr->Imm16Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
247}
248
249
250// Print 21-bit immediate value.
251void Decoder::PrintXImm21(Instruction* instr) {
252 uint32_t imm = instr->Imm21Value();
253 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000254}
255
256
257// Print 26-bit immediate value.
Ben Murdoch589d6972011-11-30 16:04:58 +0000258void Decoder::PrintXImm26(Instruction* instr) {
259 uint32_t imm = instr->Imm26Value() << kImmFieldShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000261}
262
263
264// Print 26-bit immediate value.
265void Decoder::PrintCode(Instruction* instr) {
266 if (instr->OpcodeFieldRaw() != SPECIAL)
267 return; // Not a break or trap instruction.
268 switch (instr->FunctionFieldRaw()) {
269 case BREAK: {
270 int32_t code = instr->Bits(25, 6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
272 "0x%05x (%d)", code, code);
Andrei Popescu31002712010-02-23 13:46:05 +0000273 break;
274 }
275 case TGE:
276 case TGEU:
277 case TLT:
278 case TLTU:
279 case TEQ:
280 case TNE: {
281 int32_t code = instr->Bits(15, 6);
282 out_buffer_pos_ +=
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
Andrei Popescu31002712010-02-23 13:46:05 +0000284 break;
285 }
286 default: // Not a break or trap instruction.
287 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 }
Andrei Popescu31002712010-02-23 13:46:05 +0000289}
290
291
292// Printing of instruction name.
293void Decoder::PrintInstructionName(Instruction* instr) {
294}
295
296
297// Handle all register based formatting in this function to reduce the
298// complexity of FormatOption.
299int Decoder::FormatRegister(Instruction* instr, const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000300 DCHECK(format[0] == 'r');
Ben Murdoch257744e2011-11-30 15:57:28 +0000301 if (format[1] == 's') { // 'rs: Rs register.
Steve Block44f0eee2011-05-26 01:26:41 +0100302 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000303 PrintRegister(reg);
304 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000305 } else if (format[1] == 't') { // 'rt: rt register.
Steve Block44f0eee2011-05-26 01:26:41 +0100306 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000307 PrintRegister(reg);
308 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000309 } else if (format[1] == 'd') { // 'rd: rd register.
Steve Block44f0eee2011-05-26 01:26:41 +0100310 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000311 PrintRegister(reg);
312 return 2;
313 }
314 UNREACHABLE();
315 return -1;
316}
317
318
Steve Block44f0eee2011-05-26 01:26:41 +0100319// Handle all FPUregister based formatting in this function to reduce the
Andrei Popescu31002712010-02-23 13:46:05 +0000320// complexity of FormatOption.
Steve Block44f0eee2011-05-26 01:26:41 +0100321int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 DCHECK(format[0] == 'f');
Ben Murdoch257744e2011-11-30 15:57:28 +0000323 if (format[1] == 's') { // 'fs: fs register.
Steve Block44f0eee2011-05-26 01:26:41 +0100324 int reg = instr->FsValue();
325 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000326 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000327 } else if (format[1] == 't') { // 'ft: ft register.
Steve Block44f0eee2011-05-26 01:26:41 +0100328 int reg = instr->FtValue();
329 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000330 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000331 } else if (format[1] == 'd') { // 'fd: fd register.
Steve Block44f0eee2011-05-26 01:26:41 +0100332 int reg = instr->FdValue();
333 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000334 return 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 } else if (format[1] == 'r') { // 'fr: fr register.
336 int reg = instr->FrValue();
337 PrintFPURegister(reg);
338 return 2;
Andrei Popescu31002712010-02-23 13:46:05 +0000339 }
340 UNREACHABLE();
341 return -1;
342}
343
344
345// FormatOption takes a formatting string and interprets it based on
346// the current instructions. The format string points to the first
347// character of the option string (the option escape has already been
348// consumed by the caller.) FormatOption returns the number of
349// characters that were consumed from the formatting string.
350int Decoder::FormatOption(Instruction* instr, const char* format) {
351 switch (format[0]) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000352 case 'c': { // 'code for break or trap instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 DCHECK(STRING_STARTS_WITH(format, "code"));
Andrei Popescu31002712010-02-23 13:46:05 +0000354 PrintCode(instr);
355 return 4;
356 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000357 case 'i': { // 'imm16u or 'imm26.
Andrei Popescu31002712010-02-23 13:46:05 +0000358 if (format[3] == '1') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 DCHECK(STRING_STARTS_WITH(format, "imm16"));
Andrei Popescu31002712010-02-23 13:46:05 +0000360 if (format[5] == 's') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 DCHECK(STRING_STARTS_WITH(format, "imm16s"));
Andrei Popescu31002712010-02-23 13:46:05 +0000362 PrintSImm16(instr);
363 } else if (format[5] == 'u') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364 DCHECK(STRING_STARTS_WITH(format, "imm16u"));
Andrei Popescu31002712010-02-23 13:46:05 +0000365 PrintSImm16(instr);
366 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367 DCHECK(STRING_STARTS_WITH(format, "imm16x"));
Andrei Popescu31002712010-02-23 13:46:05 +0000368 PrintXImm16(instr);
369 }
370 return 6;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371 } else if (format[3] == '2' && format[4] == '1') {
372 DCHECK(STRING_STARTS_WITH(format, "imm21x"));
373 PrintXImm21(instr);
374 return 6;
375 } else if (format[3] == '2' && format[4] == '6') {
376 DCHECK(STRING_STARTS_WITH(format, "imm26x"));
Ben Murdoch589d6972011-11-30 16:04:58 +0000377 PrintXImm26(instr);
378 return 6;
Andrei Popescu31002712010-02-23 13:46:05 +0000379 }
380 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000381 case 'r': { // 'r: registers.
Andrei Popescu31002712010-02-23 13:46:05 +0000382 return FormatRegister(instr, format);
383 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000384 case 'f': { // 'f: FPUregisters.
Steve Block44f0eee2011-05-26 01:26:41 +0100385 return FormatFPURegister(instr, format);
Andrei Popescu31002712010-02-23 13:46:05 +0000386 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000387 case 's': { // 'sa.
Steve Block44f0eee2011-05-26 01:26:41 +0100388 switch (format[1]) {
389 case 'a': {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 DCHECK(STRING_STARTS_WITH(format, "sa"));
Steve Block44f0eee2011-05-26 01:26:41 +0100391 PrintSa(instr);
392 return 2;
393 }
394 case 'd': {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000395 DCHECK(STRING_STARTS_WITH(format, "sd"));
Steve Block44f0eee2011-05-26 01:26:41 +0100396 PrintSd(instr);
397 return 2;
398 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000399 case 's': {
400 if (format[2] == '1') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 DCHECK(STRING_STARTS_WITH(format, "ss1")); /* ext size */
Ben Murdoch257744e2011-11-30 15:57:28 +0000402 PrintSs1(instr);
403 return 3;
404 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405 DCHECK(STRING_STARTS_WITH(format, "ss2")); /* ins size */
Ben Murdoch257744e2011-11-30 15:57:28 +0000406 PrintSs2(instr);
407 return 3;
408 }
409 }
Steve Block44f0eee2011-05-26 01:26:41 +0100410 }
411 }
412 case 'b': { // 'bc - Special for bc1 cc field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 DCHECK(STRING_STARTS_WITH(format, "bc"));
Steve Block44f0eee2011-05-26 01:26:41 +0100414 PrintBc(instr);
415 return 2;
416 }
417 case 'C': { // 'Cc - Special for c.xx.d cc field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 DCHECK(STRING_STARTS_WITH(format, "Cc"));
Steve Block44f0eee2011-05-26 01:26:41 +0100419 PrintCc(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000420 return 2;
421 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 }
Andrei Popescu31002712010-02-23 13:46:05 +0000423 UNREACHABLE();
424 return -1;
425}
426
427
428// Format takes a formatting string for a whole instruction and prints it into
429// the output buffer. All escaped options are handed to FormatOption to be
430// parsed further.
431void Decoder::Format(Instruction* instr, const char* format) {
432 char cur = *format++;
433 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
434 if (cur == '\'') { // Single quote is used as the formatting escape.
435 format += FormatOption(instr, format);
436 } else {
437 out_buffer_[out_buffer_pos_++] = cur;
438 }
439 cur = *format++;
440 }
441 out_buffer_[out_buffer_pos_] = '\0';
442}
443
444
445// For currently unimplemented decodings the disassembler calls Unknown(instr)
446// which will just print "unknown" of the instruction bits.
447void Decoder::Unknown(Instruction* instr) {
448 Format(instr, "unknown");
449}
450
451
452void Decoder::DecodeTypeRegister(Instruction* instr) {
453 switch (instr->OpcodeFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000454 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +0000455 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100456 case BC1: // bc1 handled in DecodeTypeImmediate.
Andrei Popescu31002712010-02-23 13:46:05 +0000457 UNREACHABLE();
458 break;
459 case MFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000460 Format(instr, "mfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000461 break;
462 case MFHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000463 Format(instr, "mfhc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000464 break;
465 case MTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000466 Format(instr, "mtc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100467 break;
468 // These are called "fs" too, although they are not FPU registers.
469 case CTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000470 Format(instr, "ctc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100471 break;
472 case CFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000473 Format(instr, "cfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000474 break;
475 case MTHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000476 Format(instr, "mthc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100477 break;
478 case D:
479 switch (instr->FunctionFieldRaw()) {
480 case ADD_D:
481 Format(instr, "add.d 'fd, 'fs, 'ft");
482 break;
483 case SUB_D:
484 Format(instr, "sub.d 'fd, 'fs, 'ft");
485 break;
486 case MUL_D:
487 Format(instr, "mul.d 'fd, 'fs, 'ft");
488 break;
489 case DIV_D:
490 Format(instr, "div.d 'fd, 'fs, 'ft");
491 break;
492 case ABS_D:
493 Format(instr, "abs.d 'fd, 'fs");
494 break;
495 case MOV_D:
496 Format(instr, "mov.d 'fd, 'fs");
497 break;
498 case NEG_D:
499 Format(instr, "neg.d 'fd, 'fs");
500 break;
501 case SQRT_D:
Ben Murdoch257744e2011-11-30 15:57:28 +0000502 Format(instr, "sqrt.d 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100503 break;
504 case CVT_W_D:
505 Format(instr, "cvt.w.d 'fd, 'fs");
506 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000507 case CVT_L_D:
508 Format(instr, "cvt.l.d 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100509 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100510 case TRUNC_W_D:
511 Format(instr, "trunc.w.d 'fd, 'fs");
512 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000513 case TRUNC_L_D:
514 Format(instr, "trunc.l.d 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100515 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100516 case ROUND_W_D:
517 Format(instr, "round.w.d 'fd, 'fs");
518 break;
519 case FLOOR_W_D:
520 Format(instr, "floor.w.d 'fd, 'fs");
521 break;
522 case CEIL_W_D:
523 Format(instr, "ceil.w.d 'fd, 'fs");
524 break;
525 case CVT_S_D:
526 Format(instr, "cvt.s.d 'fd, 'fs");
527 break;
528 case C_F_D:
529 Format(instr, "c.f.d 'fs, 'ft, 'Cc");
530 break;
531 case C_UN_D:
532 Format(instr, "c.un.d 'fs, 'ft, 'Cc");
533 break;
534 case C_EQ_D:
535 Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
536 break;
537 case C_UEQ_D:
538 Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
539 break;
540 case C_OLT_D:
541 Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
542 break;
543 case C_ULT_D:
544 Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
545 break;
546 case C_OLE_D:
547 Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
548 break;
549 case C_ULE_D:
550 Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
551 break;
552 default:
553 Format(instr, "unknown.cop1.d");
554 break;
555 }
Andrei Popescu31002712010-02-23 13:46:05 +0000556 break;
557 case S:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400558 switch (instr->FunctionFieldRaw()) {
559 case CVT_D_S:
560 Format(instr, "cvt.d.s 'fd, 'fs");
561 break;
562 default:
563 UNIMPLEMENTED_MIPS();
564 }
Andrei Popescu31002712010-02-23 13:46:05 +0000565 break;
566 case W:
567 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100568 case CVT_S_W: // Convert word to float (single).
569 Format(instr, "cvt.s.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000570 break;
571 case CVT_D_W: // Convert word to double.
Steve Block44f0eee2011-05-26 01:26:41 +0100572 Format(instr, "cvt.d.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000573 break;
574 default:
575 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100576 }
Andrei Popescu31002712010-02-23 13:46:05 +0000577 break;
578 case L:
Steve Block44f0eee2011-05-26 01:26:41 +0100579 switch (instr->FunctionFieldRaw()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 case CVT_D_L:
581 Format(instr, "cvt.d.l 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100582 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 case CVT_S_L:
584 Format(instr, "cvt.s.l 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100585 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 case CMP_UN:
587 Format(instr, "cmp.un.d 'fd, 'fs, 'ft");
588 break;
589 case CMP_EQ:
590 Format(instr, "cmp.eq.d 'fd, 'fs, 'ft");
591 break;
592 case CMP_UEQ:
593 Format(instr, "cmp.ueq.d 'fd, 'fs, 'ft");
594 break;
595 case CMP_LT:
596 Format(instr, "cmp.lt.d 'fd, 'fs, 'ft");
597 break;
598 case CMP_ULT:
599 Format(instr, "cmp.ult.d 'fd, 'fs, 'ft");
600 break;
601 case CMP_LE:
602 Format(instr, "cmp.le.d 'fd, 'fs, 'ft");
603 break;
604 case CMP_ULE:
605 Format(instr, "cmp.ule.d 'fd, 'fs, 'ft");
606 break;
607 case CMP_OR:
608 Format(instr, "cmp.or.d 'fd, 'fs, 'ft");
609 break;
610 case CMP_UNE:
611 Format(instr, "cmp.une.d 'fd, 'fs, 'ft");
612 break;
613 case CMP_NE:
614 Format(instr, "cmp.ne.d 'fd, 'fs, 'ft");
615 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100616 default:
617 UNREACHABLE();
618 }
619 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000620 case PS:
621 UNIMPLEMENTED_MIPS();
622 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000623 default:
624 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100625 }
Andrei Popescu31002712010-02-23 13:46:05 +0000626 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000627 case COP1X:
628 switch (instr->FunctionFieldRaw()) {
629 case MADD_D:
630 Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
631 break;
632 default:
633 UNREACHABLE();
634 }
635 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000636 case SPECIAL:
637 switch (instr->FunctionFieldRaw()) {
638 case JR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000639 Format(instr, "jr 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000640 break;
641 case JALR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000642 Format(instr, "jalr 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000643 break;
644 case SLL:
645 if ( 0x0 == static_cast<int>(instr->InstructionBits()))
646 Format(instr, "nop");
647 else
Ben Murdoch257744e2011-11-30 15:57:28 +0000648 Format(instr, "sll 'rd, 'rt, 'sa");
Andrei Popescu31002712010-02-23 13:46:05 +0000649 break;
650 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +0100651 if (instr->RsValue() == 0) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000652 Format(instr, "srl 'rd, 'rt, 'sa");
Steve Block44f0eee2011-05-26 01:26:41 +0100653 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654 if (IsMipsArchVariant(kMips32r2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000655 Format(instr, "rotr 'rd, 'rt, 'sa");
Steve Block44f0eee2011-05-26 01:26:41 +0100656 } else {
657 Unknown(instr);
658 }
659 }
Andrei Popescu31002712010-02-23 13:46:05 +0000660 break;
661 case SRA:
Ben Murdoch257744e2011-11-30 15:57:28 +0000662 Format(instr, "sra 'rd, 'rt, 'sa");
Andrei Popescu31002712010-02-23 13:46:05 +0000663 break;
664 case SLLV:
Ben Murdoch257744e2011-11-30 15:57:28 +0000665 Format(instr, "sllv 'rd, 'rt, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000666 break;
667 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +0100668 if (instr->SaValue() == 0) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000669 Format(instr, "srlv 'rd, 'rt, 'rs");
Steve Block44f0eee2011-05-26 01:26:41 +0100670 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671 if (IsMipsArchVariant(kMips32r2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000672 Format(instr, "rotrv 'rd, 'rt, 'rs");
Steve Block44f0eee2011-05-26 01:26:41 +0100673 } else {
674 Unknown(instr);
675 }
676 }
Andrei Popescu31002712010-02-23 13:46:05 +0000677 break;
678 case SRAV:
Ben Murdoch257744e2011-11-30 15:57:28 +0000679 Format(instr, "srav 'rd, 'rt, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000680 break;
681 case MFHI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000682 if (instr->Bits(25, 16) == 0) {
683 Format(instr, "mfhi 'rd");
684 } else {
685 if ((instr->FunctionFieldRaw() == CLZ_R6)
686 && (instr->FdValue() == 1)) {
687 Format(instr, "clz 'rd, 'rs");
688 } else if ((instr->FunctionFieldRaw() == CLO_R6)
689 && (instr->FdValue() == 1)) {
690 Format(instr, "clo 'rd, 'rs");
691 }
692 }
Andrei Popescu31002712010-02-23 13:46:05 +0000693 break;
694 case MFLO:
Ben Murdoch257744e2011-11-30 15:57:28 +0000695 Format(instr, "mflo 'rd");
Andrei Popescu31002712010-02-23 13:46:05 +0000696 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 case MULT: // @Mips32r6 == MUL_MUH.
698 if (!IsMipsArchVariant(kMips32r6)) {
699 Format(instr, "mult 'rs, 'rt");
700 } else {
701 if (instr->SaValue() == MUL_OP) {
702 Format(instr, "mul 'rd, 'rs, 'rt");
703 } else {
704 Format(instr, "muh 'rd, 'rs, 'rt");
705 }
706 }
Andrei Popescu31002712010-02-23 13:46:05 +0000707 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708 case MULTU: // @Mips32r6 == MUL_MUH_U.
709 if (!IsMipsArchVariant(kMips32r6)) {
710 Format(instr, "multu 'rs, 'rt");
711 } else {
712 if (instr->SaValue() == MUL_OP) {
713 Format(instr, "mulu 'rd, 'rs, 'rt");
714 } else {
715 Format(instr, "muhu 'rd, 'rs, 'rt");
716 }
717 }
Andrei Popescu31002712010-02-23 13:46:05 +0000718 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 case DIV: // @Mips32r6 == DIV_MOD.
720 if (!IsMipsArchVariant(kMips32r6)) {
721 Format(instr, "div 'rs, 'rt");
722 } else {
723 if (instr->SaValue() == DIV_OP) {
724 Format(instr, "div 'rd, 'rs, 'rt");
725 } else {
726 Format(instr, "mod 'rd, 'rs, 'rt");
727 }
728 }
Andrei Popescu31002712010-02-23 13:46:05 +0000729 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 case DIVU: // @Mips32r6 == DIV_MOD_U.
731 if (!IsMipsArchVariant(kMips32r6)) {
732 Format(instr, "divu 'rs, 'rt");
733 } else {
734 if (instr->SaValue() == DIV_OP) {
735 Format(instr, "divu 'rd, 'rs, 'rt");
736 } else {
737 Format(instr, "modu 'rd, 'rs, 'rt");
738 }
739 }
Andrei Popescu31002712010-02-23 13:46:05 +0000740 break;
741 case ADD:
Ben Murdoch257744e2011-11-30 15:57:28 +0000742 Format(instr, "add 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000743 break;
744 case ADDU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000745 Format(instr, "addu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000746 break;
747 case SUB:
Ben Murdoch257744e2011-11-30 15:57:28 +0000748 Format(instr, "sub 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000749 break;
750 case SUBU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000751 Format(instr, "subu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000752 break;
753 case AND:
Ben Murdoch257744e2011-11-30 15:57:28 +0000754 Format(instr, "and 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000755 break;
756 case OR:
Steve Block44f0eee2011-05-26 01:26:41 +0100757 if (0 == instr->RsValue()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000758 Format(instr, "mov 'rd, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100759 } else if (0 == instr->RtValue()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000760 Format(instr, "mov 'rd, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000761 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000762 Format(instr, "or 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000763 }
764 break;
765 case XOR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000766 Format(instr, "xor 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000767 break;
768 case NOR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000769 Format(instr, "nor 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000770 break;
771 case SLT:
Ben Murdoch257744e2011-11-30 15:57:28 +0000772 Format(instr, "slt 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000773 break;
774 case SLTU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000775 Format(instr, "sltu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000776 break;
777 case BREAK:
778 Format(instr, "break, code: 'code");
779 break;
780 case TGE:
Ben Murdoch257744e2011-11-30 15:57:28 +0000781 Format(instr, "tge 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000782 break;
783 case TGEU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000784 Format(instr, "tgeu 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000785 break;
786 case TLT:
Ben Murdoch257744e2011-11-30 15:57:28 +0000787 Format(instr, "tlt 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000788 break;
789 case TLTU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000790 Format(instr, "tltu 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000791 break;
792 case TEQ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000793 Format(instr, "teq 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000794 break;
795 case TNE:
Ben Murdoch257744e2011-11-30 15:57:28 +0000796 Format(instr, "tne 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000797 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100798 case MOVZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000799 Format(instr, "movz 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100800 break;
801 case MOVN:
Ben Murdoch257744e2011-11-30 15:57:28 +0000802 Format(instr, "movn 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100803 break;
804 case MOVCI:
805 if (instr->Bit(16)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000806 Format(instr, "movt 'rd, 'rs, 'bc");
Steve Block44f0eee2011-05-26 01:26:41 +0100807 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000808 Format(instr, "movf 'rd, 'rs, 'bc");
Steve Block44f0eee2011-05-26 01:26:41 +0100809 }
810 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811 case SELEQZ_S:
812 Format(instr, "seleqz 'rd, 'rs, 'rt");
813 break;
814 case SELNEZ_S:
815 Format(instr, "selnez 'rd, 'rs, 'rt");
816 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000817 default:
818 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100819 }
Andrei Popescu31002712010-02-23 13:46:05 +0000820 break;
821 case SPECIAL2:
822 switch (instr->FunctionFieldRaw()) {
823 case MUL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000824 Format(instr, "mul 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100825 break;
826 case CLZ:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 if (!IsMipsArchVariant(kMips32r6)) {
828 Format(instr, "clz 'rd, 'rs");
829 }
Andrei Popescu31002712010-02-23 13:46:05 +0000830 break;
831 default:
832 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100833 }
834 break;
835 case SPECIAL3:
836 switch (instr->FunctionFieldRaw()) {
837 case INS: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 if (IsMipsArchVariant(kMips32r2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000839 Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
Steve Block44f0eee2011-05-26 01:26:41 +0100840 } else {
841 Unknown(instr);
842 }
843 break;
844 }
845 case EXT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000846 if (IsMipsArchVariant(kMips32r2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000847 Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
Steve Block44f0eee2011-05-26 01:26:41 +0100848 } else {
849 Unknown(instr);
850 }
851 break;
852 }
853 default:
854 UNREACHABLE();
855 }
Andrei Popescu31002712010-02-23 13:46:05 +0000856 break;
857 default:
858 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100859 }
Andrei Popescu31002712010-02-23 13:46:05 +0000860}
861
862
863void Decoder::DecodeTypeImmediate(Instruction* instr) {
864 switch (instr->OpcodeFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100865 case COP1:
866 switch (instr->RsFieldRaw()) {
867 case BC1:
868 if (instr->FBtrueValue()) {
869 Format(instr, "bc1t 'bc, 'imm16u");
870 } else {
871 Format(instr, "bc1f 'bc, 'imm16u");
872 }
873 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874 case BC1EQZ:
875 Format(instr, "bc1eqz 'ft, 'imm16u");
876 break;
877 case BC1NEZ:
878 Format(instr, "bc1nez 'ft, 'imm16u");
879 break;
880 case W: // CMP.S instruction.
881 switch (instr->FunctionValue()) {
882 case CMP_AF:
883 Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
884 break;
885 case CMP_UN:
886 Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
887 break;
888 case CMP_EQ:
889 Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
890 break;
891 case CMP_UEQ:
892 Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
893 break;
894 case CMP_LT:
895 Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
896 break;
897 case CMP_ULT:
898 Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
899 break;
900 case CMP_LE:
901 Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
902 break;
903 case CMP_ULE:
904 Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
905 break;
906 case CMP_OR:
907 Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
908 break;
909 case CMP_UNE:
910 Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
911 break;
912 case CMP_NE:
913 Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
914 break;
915 default:
916 UNREACHABLE();
917 }
918 break;
919 case L: // CMP.D instruction.
920 switch (instr->FunctionValue()) {
921 case CMP_AF:
922 Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
923 break;
924 case CMP_UN:
925 Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
926 break;
927 case CMP_EQ:
928 Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
929 break;
930 case CMP_UEQ:
931 Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
932 break;
933 case CMP_LT:
934 Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
935 break;
936 case CMP_ULT:
937 Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
938 break;
939 case CMP_LE:
940 Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
941 break;
942 case CMP_ULE:
943 Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
944 break;
945 case CMP_OR:
946 Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
947 break;
948 case CMP_UNE:
949 Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
950 break;
951 case CMP_NE:
952 Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
953 break;
954 default:
955 UNREACHABLE();
956 }
957 break;
958 case S:
959 switch (instr->FunctionValue()) {
960 case SEL:
961 Format(instr, "sel.S 'ft, 'fs, 'fd");
962 break;
963 case SELEQZ_C:
964 Format(instr, "seleqz.S 'ft, 'fs, 'fd");
965 break;
966 case SELNEZ_C:
967 Format(instr, "selnez.S 'ft, 'fs, 'fd");
968 break;
969 case MIN:
970 Format(instr, "min.S 'ft, 'fs, 'fd");
971 break;
972 case MINA:
973 Format(instr, "mina.S 'ft, 'fs, 'fd");
974 break;
975 case MAX:
976 Format(instr, "max.S 'ft, 'fs, 'fd");
977 break;
978 case MAXA:
979 Format(instr, "maxa.S 'ft, 'fs, 'fd");
980 break;
981 default:
982 UNREACHABLE();
983 }
984 break;
985 case D:
986 switch (instr->FunctionValue()) {
987 case SEL:
988 Format(instr, "sel.D 'ft, 'fs, 'fd");
989 break;
990 case SELEQZ_C:
991 Format(instr, "seleqz.D 'ft, 'fs, 'fd");
992 break;
993 case SELNEZ_C:
994 Format(instr, "selnez.D 'ft, 'fs, 'fd");
995 break;
996 case MIN:
997 Format(instr, "min.D 'ft, 'fs, 'fd");
998 break;
999 case MINA:
1000 Format(instr, "mina.D 'ft, 'fs, 'fd");
1001 break;
1002 case MAX:
1003 Format(instr, "max.D 'ft, 'fs, 'fd");
1004 break;
1005 case MAXA:
1006 Format(instr, "maxa.D 'ft, 'fs, 'fd");
1007 break;
1008 default:
1009 UNREACHABLE();
1010 }
1011 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001012 default:
1013 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 }
1015
Steve Block44f0eee2011-05-26 01:26:41 +01001016 break; // Case COP1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00001018 case REGIMM:
1019 switch (instr->RtFieldRaw()) {
1020 case BLTZ:
Ben Murdoch257744e2011-11-30 15:57:28 +00001021 Format(instr, "bltz 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001022 break;
1023 case BLTZAL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001024 Format(instr, "bltzal 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001025 break;
1026 case BGEZ:
Ben Murdoch257744e2011-11-30 15:57:28 +00001027 Format(instr, "bgez 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001028 break;
1029 case BGEZAL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001030 Format(instr, "bgezal 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001031 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032 case BGEZALL:
1033 Format(instr, "bgezall 'rs, 'imm16u");
1034 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001035 default:
1036 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001037 }
1038 break; // Case REGIMM.
Andrei Popescu31002712010-02-23 13:46:05 +00001039 // ------------- Branch instructions.
1040 case BEQ:
Ben Murdoch257744e2011-11-30 15:57:28 +00001041 Format(instr, "beq 'rs, 'rt, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001042 break;
1043 case BNE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001044 Format(instr, "bne 'rs, 'rt, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001045 break;
1046 case BLEZ:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 if ((instr->RtFieldRaw() == 0)
1048 && (instr->RsFieldRaw() != 0)) {
1049 Format(instr, "blez 'rs, 'imm16u");
1050 } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1051 && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1052 Format(instr, "bgeuc 'rs, 'rt, 'imm16u");
1053 } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1054 && (instr->RtFieldRaw() != 0)) {
1055 Format(instr, "bgezalc 'rs, 'imm16u");
1056 } else if ((instr->RsFieldRaw() == 0)
1057 && (instr->RtFieldRaw() != 0)) {
1058 Format(instr, "blezalc 'rs, 'imm16u");
1059 } else {
1060 UNREACHABLE();
1061 }
Andrei Popescu31002712010-02-23 13:46:05 +00001062 break;
1063 case BGTZ:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 if ((instr->RtFieldRaw() == 0)
1065 && (instr->RsFieldRaw() != 0)) {
1066 Format(instr, "bgtz 'rs, 'imm16u");
1067 } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1068 && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1069 Format(instr, "bltuc 'rs, 'rt, 'imm16u");
1070 } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1071 && (instr->RtFieldRaw() != 0)) {
1072 Format(instr, "bltzalc 'rt, 'imm16u");
1073 } else if ((instr->RsFieldRaw() == 0)
1074 && (instr->RtFieldRaw() != 0)) {
1075 Format(instr, "bgtzalc 'rt, 'imm16u");
1076 } else {
1077 UNREACHABLE();
1078 }
1079 break;
1080 case BLEZL:
1081 if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1082 && (instr->RtFieldRaw() != 0)) {
1083 Format(instr, "bgezc 'rt, 'imm16u");
1084 } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1085 && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1086 Format(instr, "bgec 'rs, 'rt, 'imm16u");
1087 } else if ((instr->RsFieldRaw() == 0)
1088 && (instr->RtFieldRaw() != 0)) {
1089 Format(instr, "blezc 'rt, 'imm16u");
1090 } else {
1091 UNREACHABLE();
1092 }
1093 break;
1094 case BGTZL:
1095 if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1096 && (instr->RtFieldRaw() != 0)) {
1097 Format(instr, "bltzc 'rt, 'imm16u");
1098 } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1099 && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1100 Format(instr, "bltc 'rs, 'rt, 'imm16u");
1101 } else if ((instr->RsFieldRaw() == 0)
1102 && (instr->RtFieldRaw() != 0)) {
1103 Format(instr, "bgtzc 'rt, 'imm16u");
1104 } else {
1105 UNREACHABLE();
1106 }
1107 break;
1108 case BEQZC:
1109 if (instr->RsFieldRaw() != 0) {
1110 Format(instr, "beqzc 'rs, 'imm21x");
1111 }
1112 break;
1113 case BNEZC:
1114 if (instr->RsFieldRaw() != 0) {
1115 Format(instr, "bnezc 'rs, 'imm21x");
1116 }
Andrei Popescu31002712010-02-23 13:46:05 +00001117 break;
1118 // ------------- Arithmetic instructions.
1119 case ADDI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 if (!IsMipsArchVariant(kMips32r6)) {
1121 Format(instr, "addi 'rt, 'rs, 'imm16s");
1122 } else {
1123 // Check if BOVC or BEQC instruction.
1124 if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1125 Format(instr, "bovc 'rs, 'rt, 'imm16s");
1126 } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1127 Format(instr, "beqc 'rs, 'rt, 'imm16s");
1128 } else {
1129 UNREACHABLE();
1130 }
1131 }
1132 break;
1133 case DADDI:
1134 if (IsMipsArchVariant(kMips32r6)) {
1135 // Check if BNVC or BNEC instruction.
1136 if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1137 Format(instr, "bnvc 'rs, 'rt, 'imm16s");
1138 } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1139 Format(instr, "bnec 'rs, 'rt, 'imm16s");
1140 } else {
1141 UNREACHABLE();
1142 }
1143 }
Andrei Popescu31002712010-02-23 13:46:05 +00001144 break;
1145 case ADDIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001146 Format(instr, "addiu 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001147 break;
1148 case SLTI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001149 Format(instr, "slti 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001150 break;
1151 case SLTIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001152 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001153 break;
1154 case ANDI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001155 Format(instr, "andi 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001156 break;
1157 case ORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001158 Format(instr, "ori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001159 break;
1160 case XORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001161 Format(instr, "xori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001162 break;
1163 case LUI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 if (!IsMipsArchVariant(kMips32r6)) {
1165 Format(instr, "lui 'rt, 'imm16x");
1166 } else {
1167 if (instr->RsValue() != 0) {
1168 Format(instr, "aui 'rt, 'imm16x");
1169 } else {
1170 Format(instr, "lui 'rt, 'imm16x");
1171 }
1172 }
Andrei Popescu31002712010-02-23 13:46:05 +00001173 break;
1174 // ------------- Memory instructions.
1175 case LB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001176 Format(instr, "lb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001177 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001178 case LH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001179 Format(instr, "lh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001180 break;
1181 case LWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001182 Format(instr, "lwl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001183 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001184 case LW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001185 Format(instr, "lw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001186 break;
1187 case LBU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001188 Format(instr, "lbu 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001189 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001190 case LHU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001191 Format(instr, "lhu 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001192 break;
1193 case LWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001194 Format(instr, "lwr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001195 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 case PREF:
1197 Format(instr, "pref 'rt, 'imm16s('rs)");
1198 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001199 case SB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001200 Format(instr, "sb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001201 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001202 case SH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001203 Format(instr, "sh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001204 break;
1205 case SWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001206 Format(instr, "swl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001207 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001208 case SW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001209 Format(instr, "sw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001210 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001211 case SWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001212 Format(instr, "swr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001213 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001214 case LWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001215 Format(instr, "lwc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001216 break;
1217 case LDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001218 Format(instr, "ldc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001219 break;
1220 case SWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001221 Format(instr, "swc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001222 break;
1223 case SDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001224 Format(instr, "sdc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001225 break;
1226 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 printf("a 0x%x \n", instr->OpcodeFieldRaw());
Andrei Popescu31002712010-02-23 13:46:05 +00001228 UNREACHABLE();
1229 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 }
Andrei Popescu31002712010-02-23 13:46:05 +00001231}
1232
1233
1234void Decoder::DecodeTypeJump(Instruction* instr) {
1235 switch (instr->OpcodeFieldRaw()) {
1236 case J:
Ben Murdoch589d6972011-11-30 16:04:58 +00001237 Format(instr, "j 'imm26x");
Andrei Popescu31002712010-02-23 13:46:05 +00001238 break;
1239 case JAL:
Ben Murdoch589d6972011-11-30 16:04:58 +00001240 Format(instr, "jal 'imm26x");
Andrei Popescu31002712010-02-23 13:46:05 +00001241 break;
1242 default:
1243 UNREACHABLE();
1244 }
1245}
1246
1247
1248// Disassemble the instruction at *instr_ptr into the output buffer.
Ben Murdoch257744e2011-11-30 15:57:28 +00001249int Decoder::InstructionDecode(byte* instr_ptr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001250 Instruction* instr = Instruction::At(instr_ptr);
1251 // Print raw instruction bytes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
1253 "%08x ",
1254 instr->InstructionBits());
Andrei Popescu31002712010-02-23 13:46:05 +00001255 switch (instr->InstructionType()) {
1256 case Instruction::kRegisterType: {
1257 DecodeTypeRegister(instr);
1258 break;
1259 }
1260 case Instruction::kImmediateType: {
1261 DecodeTypeImmediate(instr);
1262 break;
1263 }
1264 case Instruction::kJumpType: {
1265 DecodeTypeJump(instr);
1266 break;
1267 }
1268 default: {
Ben Murdoch589d6972011-11-30 16:04:58 +00001269 Format(instr, "UNSUPPORTED");
Andrei Popescu31002712010-02-23 13:46:05 +00001270 UNSUPPORTED_MIPS();
1271 }
1272 }
Steve Block44f0eee2011-05-26 01:26:41 +01001273 return Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00001274}
1275
1276
Steve Block44f0eee2011-05-26 01:26:41 +01001277} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +00001278
1279
1280
1281//------------------------------------------------------------------------------
1282
1283namespace disasm {
1284
Ben Murdoch257744e2011-11-30 15:57:28 +00001285const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001286 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001287 return tmp_buffer_.start();
Andrei Popescu31002712010-02-23 13:46:05 +00001288}
1289
1290
Ben Murdoch257744e2011-11-30 15:57:28 +00001291const char* NameConverter::NameOfConstant(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001292 return NameOfAddress(addr);
1293}
1294
1295
1296const char* NameConverter::NameOfCPURegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001297 return v8::internal::Registers::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001298}
1299
1300
1301const char* NameConverter::NameOfXMMRegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001302 return v8::internal::FPURegisters::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001303}
1304
1305
1306const char* NameConverter::NameOfByteCPURegister(int reg) const {
Ben Murdoch257744e2011-11-30 15:57:28 +00001307 UNREACHABLE(); // MIPS does not have the concept of a byte register.
Andrei Popescu31002712010-02-23 13:46:05 +00001308 return "nobytereg";
1309}
1310
1311
Ben Murdoch257744e2011-11-30 15:57:28 +00001312const char* NameConverter::NameInCode(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001313 // The default name converter is called for unknown code. So we will not try
1314 // to access any memory.
1315 return "";
1316}
1317
1318
1319//------------------------------------------------------------------------------
1320
1321Disassembler::Disassembler(const NameConverter& converter)
1322 : converter_(converter) {}
1323
1324
1325Disassembler::~Disassembler() {}
1326
1327
1328int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +00001329 byte* instruction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001330 v8::internal::Decoder d(converter_, buffer);
Andrei Popescu31002712010-02-23 13:46:05 +00001331 return d.InstructionDecode(instruction);
1332}
1333
1334
Steve Block44f0eee2011-05-26 01:26:41 +01001335// The MIPS assembler does not currently use constant pools.
Ben Murdoch257744e2011-11-30 15:57:28 +00001336int Disassembler::ConstantPoolSizeAt(byte* instruction) {
Andrei Popescu31002712010-02-23 13:46:05 +00001337 return -1;
1338}
1339
1340
Ben Murdoch257744e2011-11-30 15:57:28 +00001341void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Andrei Popescu31002712010-02-23 13:46:05 +00001342 NameConverter converter;
1343 Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00001344 for (byte* pc = begin; pc < end;) {
Andrei Popescu31002712010-02-23 13:46:05 +00001345 v8::internal::EmbeddedVector<char, 128> buffer;
1346 buffer[0] = '\0';
Ben Murdoch257744e2011-11-30 15:57:28 +00001347 byte* prev_pc = pc;
Andrei Popescu31002712010-02-23 13:46:05 +00001348 pc += d.InstructionDecode(buffer, pc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 v8::internal::PrintF(f, "%p %08x %s\n",
1350 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00001351 }
1352}
1353
Steve Block44f0eee2011-05-26 01:26:41 +01001354
Andrei Popescu31002712010-02-23 13:46:05 +00001355#undef UNSUPPORTED
1356
1357} // namespace disasm
1358
Leon Clarkef7060e22010-06-03 12:02:55 +01001359#endif // V8_TARGET_ARCH_MIPS