blob: c0a02a8b9c55d2552626e7cf33f6cdef48b07610 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
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);
13// for (byte* pc = begin; pc < end;) {
14// v8::internal::EmbeddedVector<char, 256> buffer;
15// byte* prev_pc = pc;
16// pc += d.InstructionDecode(buffer, pc);
17// 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>
27#include <stdarg.h>
28#include <stdio.h>
29#include <string.h>
30
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031#if V8_TARGET_ARCH_PPC
32
33#include "src/base/platform/platform.h"
34#include "src/disasm.h"
35#include "src/macro-assembler.h"
36#include "src/ppc/constants-ppc.h"
37
38
39namespace v8 {
40namespace internal {
41
Ben Murdoch61f157c2016-09-16 13:49:30 +010042const auto GetRegConfig = RegisterConfiguration::Crankshaft;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040043
44//------------------------------------------------------------------------------
45
46// Decoder decodes and disassembles instructions into an output buffer.
47// It uses the converter to convert register names and call destinations into
48// more informative description.
49class Decoder {
50 public:
51 Decoder(const disasm::NameConverter& converter, Vector<char> out_buffer)
52 : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) {
53 out_buffer_[out_buffer_pos_] = '\0';
54 }
55
56 ~Decoder() {}
57
58 // Writes one disassembled instruction into 'buffer' (0-terminated).
59 // Returns the length of the disassembled machine instruction in bytes.
60 int InstructionDecode(byte* instruction);
61
62 private:
63 // Bottleneck functions to print into the out_buffer.
64 void PrintChar(const char ch);
65 void Print(const char* str);
66
67 // Printing of common values.
68 void PrintRegister(int reg);
69 void PrintDRegister(int reg);
70 int FormatFPRegister(Instruction* instr, const char* format);
71 void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
72
73 // Handle formatting of instructions and their options.
74 int FormatRegister(Instruction* instr, const char* option);
75 int FormatOption(Instruction* instr, const char* option);
76 void Format(Instruction* instr, const char* format);
77 void Unknown(Instruction* instr);
78 void UnknownFormat(Instruction* instr, const char* opcname);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040079
80 void DecodeExt1(Instruction* instr);
81 void DecodeExt2(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 void DecodeExt3(Instruction* instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 void DecodeExt4(Instruction* instr);
84 void DecodeExt5(Instruction* instr);
85
86 const disasm::NameConverter& converter_;
87 Vector<char> out_buffer_;
88 int out_buffer_pos_;
89
90 DISALLOW_COPY_AND_ASSIGN(Decoder);
91};
92
93
94// Support for assertions in the Decoder formatting functions.
95#define STRING_STARTS_WITH(string, compare_string) \
96 (strncmp(string, compare_string, strlen(compare_string)) == 0)
97
98
99// Append the ch to the output buffer.
100void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; }
101
102
103// Append the str to the output buffer.
104void Decoder::Print(const char* str) {
105 char cur = *str++;
106 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
107 PrintChar(cur);
108 cur = *str++;
109 }
110 out_buffer_[out_buffer_pos_] = 0;
111}
112
113
114// Print the register name according to the active name converter.
115void Decoder::PrintRegister(int reg) {
116 Print(converter_.NameOfCPURegister(reg));
117}
118
119
120// Print the double FP register name according to the active name converter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121void Decoder::PrintDRegister(int reg) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100122 Print(GetRegConfig()->GetDoubleRegisterName(reg));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124
125
126// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
127// the FormatOption method.
128void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
129 switch (svc) {
130 case kCallRtRedirected:
131 Print("call rt redirected");
132 return;
133 case kBreakpoint:
134 Print("breakpoint");
135 return;
136 default:
137 if (svc >= kStopCode) {
138 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d - 0x%x",
139 svc & kStopCodeMask, svc & kStopCodeMask);
140 } else {
141 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", svc);
142 }
143 return;
144 }
145}
146
147
148// Handle all register based formatting in this function to reduce the
149// complexity of FormatOption.
150int Decoder::FormatRegister(Instruction* instr, const char* format) {
151 DCHECK(format[0] == 'r');
152
153 if ((format[1] == 't') || (format[1] == 's')) { // 'rt & 'rs register
154 int reg = instr->RTValue();
155 PrintRegister(reg);
156 return 2;
157 } else if (format[1] == 'a') { // 'ra: RA register
158 int reg = instr->RAValue();
159 PrintRegister(reg);
160 return 2;
161 } else if (format[1] == 'b') { // 'rb: RB register
162 int reg = instr->RBValue();
163 PrintRegister(reg);
164 return 2;
165 }
166
167 UNREACHABLE();
168 return -1;
169}
170
171
172// Handle all FP register based formatting in this function to reduce the
173// complexity of FormatOption.
174int Decoder::FormatFPRegister(Instruction* instr, const char* format) {
175 DCHECK(format[0] == 'D');
176
177 int retval = 2;
178 int reg = -1;
179 if (format[1] == 't') {
180 reg = instr->RTValue();
181 } else if (format[1] == 'a') {
182 reg = instr->RAValue();
183 } else if (format[1] == 'b') {
184 reg = instr->RBValue();
185 } else if (format[1] == 'c') {
186 reg = instr->RCValue();
187 } else {
188 UNREACHABLE();
189 }
190
191 PrintDRegister(reg);
192
193 return retval;
194}
195
196
197// FormatOption takes a formatting string and interprets it based on
198// the current instructions. The format string points to the first
199// character of the option string (the option escape has already been
200// consumed by the caller.) FormatOption returns the number of
201// characters that were consumed from the formatting string.
202int Decoder::FormatOption(Instruction* instr, const char* format) {
203 switch (format[0]) {
204 case 'o': {
205 if (instr->Bit(10) == 1) {
206 Print("o");
207 }
208 return 1;
209 }
210 case '.': {
211 if (instr->Bit(0) == 1) {
212 Print(".");
213 } else {
214 Print(" "); // ensure consistent spacing
215 }
216 return 1;
217 }
218 case 'r': {
219 return FormatRegister(instr, format);
220 }
221 case 'D': {
222 return FormatFPRegister(instr, format);
223 }
224 case 'i': { // int16
225 int32_t value = (instr->Bits(15, 0) << 16) >> 16;
226 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
227 return 5;
228 }
229 case 'u': { // uint16
230 int32_t value = instr->Bits(15, 0);
231 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
232 return 6;
233 }
234 case 'l': {
235 // Link (LK) Bit 0
236 if (instr->Bit(0) == 1) {
237 Print("l");
238 }
239 return 1;
240 }
241 case 'a': {
242 // Absolute Address Bit 1
243 if (instr->Bit(1) == 1) {
244 Print("a");
245 }
246 return 1;
247 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 case 'c': { // 'cr: condition register of branch instruction
249 int code = instr->Bits(20, 18);
250 if (code != 7) {
251 out_buffer_pos_ +=
252 SNPrintF(out_buffer_ + out_buffer_pos_, " cr%d", code);
253 }
254 return 2;
255 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 case 't': { // 'target: target of branch instructions
257 // target26 or target16
258 DCHECK(STRING_STARTS_WITH(format, "target"));
259 if ((format[6] == '2') && (format[7] == '6')) {
260 int off = ((instr->Bits(25, 2)) << 8) >> 6;
261 out_buffer_pos_ += SNPrintF(
262 out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
263 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
264 return 8;
265 } else if ((format[6] == '1') && (format[7] == '6')) {
266 int off = ((instr->Bits(15, 2)) << 18) >> 16;
267 out_buffer_pos_ += SNPrintF(
268 out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
269 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
270 return 8;
271 }
272 case 's': {
273 DCHECK(format[1] == 'h');
274 int32_t value = 0;
275 int32_t opcode = instr->OpcodeValue() << 26;
276 int32_t sh = instr->Bits(15, 11);
277 if (opcode == EXT5 ||
278 (opcode == EXT2 && instr->Bits(10, 2) << 2 == SRADIX)) {
279 // SH Bits 1 and 15-11 (split field)
280 value = (sh | (instr->Bit(1) << 5));
281 } else {
282 // SH Bits 15-11
283 value = (sh << 26) >> 26;
284 }
285 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
286 return 2;
287 }
288 case 'm': {
289 int32_t value = 0;
290 if (format[1] == 'e') {
291 if (instr->OpcodeValue() << 26 != EXT5) {
292 // ME Bits 10-6
293 value = (instr->Bits(10, 6) << 26) >> 26;
294 } else {
295 // ME Bits 5 and 10-6 (split field)
296 value = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
297 }
298 } else if (format[1] == 'b') {
299 if (instr->OpcodeValue() << 26 != EXT5) {
300 // MB Bits 5-1
301 value = (instr->Bits(5, 1) << 26) >> 26;
302 } else {
303 // MB Bits 5 and 10-6 (split field)
304 value = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
305 }
306 } else {
307 UNREACHABLE(); // bad format
308 }
309 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
310 return 2;
311 }
312 }
313#if V8_TARGET_ARCH_PPC64
314 case 'd': { // ds value for offset
315 int32_t value = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
316 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
317 return 1;
318 }
319#endif
320 default: {
321 UNREACHABLE();
322 break;
323 }
324 }
325
326 UNREACHABLE();
327 return -1;
328}
329
330
331// Format takes a formatting string for a whole instruction and prints it into
332// the output buffer. All escaped options are handed to FormatOption to be
333// parsed further.
334void Decoder::Format(Instruction* instr, const char* format) {
335 char cur = *format++;
336 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
337 if (cur == '\'') { // Single quote is used as the formatting escape.
338 format += FormatOption(instr, format);
339 } else {
340 out_buffer_[out_buffer_pos_++] = cur;
341 }
342 cur = *format++;
343 }
344 out_buffer_[out_buffer_pos_] = '\0';
345}
346
347
348// The disassembler may end up decoding data inlined in the code. We do not want
349// it to crash if the data does not ressemble any known instruction.
350#define VERIFY(condition) \
351 if (!(condition)) { \
352 Unknown(instr); \
353 return; \
354 }
355
356
357// For currently unimplemented decodings the disassembler calls Unknown(instr)
358// which will just print "unknown" of the instruction bits.
359void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); }
360
361
362// For currently unimplemented decodings the disassembler calls
363// UnknownFormat(instr) which will just print opcode name of the
364// instruction bits.
365void Decoder::UnknownFormat(Instruction* instr, const char* name) {
366 char buffer[100];
367 snprintf(buffer, sizeof(buffer), "%s (unknown-format)", name);
368 Format(instr, buffer);
369}
370
371
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372void Decoder::DecodeExt1(Instruction* instr) {
373 switch (instr->Bits(10, 1) << 1) {
374 case MCRF: {
375 UnknownFormat(instr, "mcrf"); // not used by V8
376 break;
377 }
378 case BCLRX: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 int bo = instr->Bits(25, 21) << 21;
380 int bi = instr->Bits(20, 16);
381 CRBit cond = static_cast<CRBit>(bi & (CRWIDTH - 1));
382 switch (bo) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400383 case DCBNZF: {
384 UnknownFormat(instr, "bclrx-dcbnzf");
385 break;
386 }
387 case DCBEZF: {
388 UnknownFormat(instr, "bclrx-dcbezf");
389 break;
390 }
391 case BF: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 switch (cond) {
393 case CR_EQ:
394 Format(instr, "bnelr'l'cr");
395 break;
396 case CR_GT:
397 Format(instr, "blelr'l'cr");
398 break;
399 case CR_LT:
400 Format(instr, "bgelr'l'cr");
401 break;
402 case CR_SO:
403 Format(instr, "bnsolr'l'cr");
404 break;
405 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400406 break;
407 }
408 case DCBNZT: {
409 UnknownFormat(instr, "bclrx-dcbbzt");
410 break;
411 }
412 case DCBEZT: {
413 UnknownFormat(instr, "bclrx-dcbnezt");
414 break;
415 }
416 case BT: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 switch (cond) {
418 case CR_EQ:
419 Format(instr, "beqlr'l'cr");
420 break;
421 case CR_GT:
422 Format(instr, "bgtlr'l'cr");
423 break;
424 case CR_LT:
425 Format(instr, "bltlr'l'cr");
426 break;
427 case CR_SO:
428 Format(instr, "bsolr'l'cr");
429 break;
430 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400431 break;
432 }
433 case DCBNZ: {
434 UnknownFormat(instr, "bclrx-dcbnz");
435 break;
436 }
437 case DCBEZ: {
438 UnknownFormat(instr, "bclrx-dcbez"); // not used by V8
439 break;
440 }
441 case BA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000442 Format(instr, "blr'l");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400443 break;
444 }
445 }
446 break;
447 }
448 case BCCTRX: {
449 switch (instr->Bits(25, 21) << 21) {
450 case DCBNZF: {
451 UnknownFormat(instr, "bcctrx-dcbnzf");
452 break;
453 }
454 case DCBEZF: {
455 UnknownFormat(instr, "bcctrx-dcbezf");
456 break;
457 }
458 case BF: {
459 UnknownFormat(instr, "bcctrx-bf");
460 break;
461 }
462 case DCBNZT: {
463 UnknownFormat(instr, "bcctrx-dcbnzt");
464 break;
465 }
466 case DCBEZT: {
467 UnknownFormat(instr, "bcctrx-dcbezf");
468 break;
469 }
470 case BT: {
471 UnknownFormat(instr, "bcctrx-bt");
472 break;
473 }
474 case DCBNZ: {
475 UnknownFormat(instr, "bcctrx-dcbnz");
476 break;
477 }
478 case DCBEZ: {
479 UnknownFormat(instr, "bcctrx-dcbez");
480 break;
481 }
482 case BA: {
483 if (instr->Bit(0) == 1) {
484 Format(instr, "bctrl");
485 } else {
486 Format(instr, "bctr");
487 }
488 break;
489 }
490 default: { UNREACHABLE(); }
491 }
492 break;
493 }
494 case CRNOR: {
495 Format(instr, "crnor (stuff)");
496 break;
497 }
498 case RFI: {
499 Format(instr, "rfi (stuff)");
500 break;
501 }
502 case CRANDC: {
503 Format(instr, "crandc (stuff)");
504 break;
505 }
506 case ISYNC: {
507 Format(instr, "isync (stuff)");
508 break;
509 }
510 case CRXOR: {
511 Format(instr, "crxor (stuff)");
512 break;
513 }
514 case CRNAND: {
515 UnknownFormat(instr, "crnand");
516 break;
517 }
518 case CRAND: {
519 UnknownFormat(instr, "crand");
520 break;
521 }
522 case CREQV: {
523 UnknownFormat(instr, "creqv");
524 break;
525 }
526 case CRORC: {
527 UnknownFormat(instr, "crorc");
528 break;
529 }
530 case CROR: {
531 UnknownFormat(instr, "cror");
532 break;
533 }
534 default: {
535 Unknown(instr); // not used by V8
536 }
537 }
538}
539
540
541void Decoder::DecodeExt2(Instruction* instr) {
542 // Some encodings are 10-1 bits, handle those first
543 switch (instr->Bits(10, 1) << 1) {
544 case SRWX: {
545 Format(instr, "srw'. 'ra, 'rs, 'rb");
546 return;
547 }
548#if V8_TARGET_ARCH_PPC64
549 case SRDX: {
550 Format(instr, "srd'. 'ra, 'rs, 'rb");
551 return;
552 }
553#endif
554 case SRAW: {
555 Format(instr, "sraw'. 'ra, 'rs, 'rb");
556 return;
557 }
558#if V8_TARGET_ARCH_PPC64
559 case SRAD: {
560 Format(instr, "srad'. 'ra, 'rs, 'rb");
561 return;
562 }
563#endif
564 case SRAWIX: {
565 Format(instr, "srawi'. 'ra,'rs,'sh");
566 return;
567 }
568 case EXTSH: {
569 Format(instr, "extsh'. 'ra, 'rs");
570 return;
571 }
572#if V8_TARGET_ARCH_PPC64
573 case EXTSW: {
574 Format(instr, "extsw'. 'ra, 'rs");
575 return;
576 }
577#endif
578 case EXTSB: {
579 Format(instr, "extsb'. 'ra, 'rs");
580 return;
581 }
582 case LFSX: {
583 Format(instr, "lfsx 'rt, 'ra, 'rb");
584 return;
585 }
586 case LFSUX: {
587 Format(instr, "lfsux 'rt, 'ra, 'rb");
588 return;
589 }
590 case LFDX: {
591 Format(instr, "lfdx 'rt, 'ra, 'rb");
592 return;
593 }
594 case LFDUX: {
595 Format(instr, "lfdux 'rt, 'ra, 'rb");
596 return;
597 }
598 case STFSX: {
599 Format(instr, "stfsx 'rs, 'ra, 'rb");
600 return;
601 }
602 case STFSUX: {
603 Format(instr, "stfsux 'rs, 'ra, 'rb");
604 return;
605 }
606 case STFDX: {
607 Format(instr, "stfdx 'rs, 'ra, 'rb");
608 return;
609 }
610 case STFDUX: {
611 Format(instr, "stfdux 'rs, 'ra, 'rb");
612 return;
613 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 case POPCNTW: {
615 Format(instr, "popcntw 'ra, 'rs");
616 return;
617 }
618#if V8_TARGET_ARCH_PPC64
619 case POPCNTD: {
620 Format(instr, "popcntd 'ra, 'rs");
621 return;
622 }
623#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400624 }
625
626 switch (instr->Bits(10, 2) << 2) {
627 case SRADIX: {
628 Format(instr, "sradi'. 'ra,'rs,'sh");
629 return;
630 }
631 }
632
633 // ?? are all of these xo_form?
634 switch (instr->Bits(9, 1) << 1) {
635 case CMP: {
636#if V8_TARGET_ARCH_PPC64
637 if (instr->Bit(21)) {
638#endif
639 Format(instr, "cmp 'ra, 'rb");
640#if V8_TARGET_ARCH_PPC64
641 } else {
642 Format(instr, "cmpw 'ra, 'rb");
643 }
644#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 }
647 case SLWX: {
648 Format(instr, "slw'. 'ra, 'rs, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400650 }
651#if V8_TARGET_ARCH_PPC64
652 case SLDX: {
653 Format(instr, "sld'. 'ra, 'rs, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400655 }
656#endif
657 case SUBFCX: {
658 Format(instr, "subfc'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400660 }
Ben Murdochda12d292016-06-02 14:46:10 +0100661 case SUBFEX: {
662 Format(instr, "subfe'. 'rt, 'ra, 'rb");
663 return;
664 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400665 case ADDCX: {
666 Format(instr, "addc'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400668 }
Ben Murdochda12d292016-06-02 14:46:10 +0100669 case ADDEX: {
670 Format(instr, "adde'. 'rt, 'ra, 'rb");
671 return;
672 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400673 case CNTLZWX: {
674 Format(instr, "cntlzw'. 'ra, 'rs");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400676 }
677#if V8_TARGET_ARCH_PPC64
678 case CNTLZDX: {
679 Format(instr, "cntlzd'. 'ra, 'rs");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400681 }
682#endif
683 case ANDX: {
684 Format(instr, "and'. 'ra, 'rs, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400686 }
687 case ANDCX: {
688 Format(instr, "andc'. 'ra, 'rs, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400690 }
691 case CMPL: {
692#if V8_TARGET_ARCH_PPC64
693 if (instr->Bit(21)) {
694#endif
695 Format(instr, "cmpl 'ra, 'rb");
696#if V8_TARGET_ARCH_PPC64
697 } else {
698 Format(instr, "cmplw 'ra, 'rb");
699 }
700#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400702 }
703 case NEGX: {
704 Format(instr, "neg'. 'rt, 'ra");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400706 }
707 case NORX: {
708 Format(instr, "nor'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400710 }
711 case SUBFX: {
712 Format(instr, "subf'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400714 }
715 case MULHWX: {
716 Format(instr, "mulhw'o'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400718 }
719 case ADDZEX: {
720 Format(instr, "addze'. 'rt, 'ra");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000721 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400722 }
723 case MULLW: {
724 Format(instr, "mullw'o'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 }
727#if V8_TARGET_ARCH_PPC64
728 case MULLD: {
729 Format(instr, "mulld'o'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731 }
732#endif
733 case DIVW: {
734 Format(instr, "divw'o'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 return;
736 }
737 case DIVWU: {
738 Format(instr, "divwu'o'. 'rt, 'ra, 'rb");
739 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400740 }
741#if V8_TARGET_ARCH_PPC64
742 case DIVD: {
743 Format(instr, "divd'o'. 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400745 }
746#endif
747 case ADDX: {
748 Format(instr, "add'o 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400750 }
751 case XORX: {
752 Format(instr, "xor'. 'ra, 'rs, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400754 }
755 case ORX: {
756 if (instr->RTValue() == instr->RBValue()) {
757 Format(instr, "mr 'ra, 'rb");
758 } else {
759 Format(instr, "or 'ra, 'rs, 'rb");
760 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400762 }
763 case MFSPR: {
764 int spr = instr->Bits(20, 11);
765 if (256 == spr) {
766 Format(instr, "mflr 'rt");
767 } else {
768 Format(instr, "mfspr 'rt ??");
769 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400771 }
772 case MTSPR: {
773 int spr = instr->Bits(20, 11);
774 if (256 == spr) {
775 Format(instr, "mtlr 'rt");
776 } else if (288 == spr) {
777 Format(instr, "mtctr 'rt");
778 } else {
779 Format(instr, "mtspr 'rt ??");
780 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 }
783 case MFCR: {
784 Format(instr, "mfcr 'rt");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400786 }
787 case STWX: {
788 Format(instr, "stwx 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400790 }
791 case STWUX: {
792 Format(instr, "stwux 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400794 }
795 case STBX: {
796 Format(instr, "stbx 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400798 }
799 case STBUX: {
800 Format(instr, "stbux 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400802 }
803 case STHX: {
804 Format(instr, "sthx 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000805 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400806 }
807 case STHUX: {
808 Format(instr, "sthux 'rs, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400810 }
811 case LWZX: {
812 Format(instr, "lwzx 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400814 }
815 case LWZUX: {
816 Format(instr, "lwzux 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 return;
818 }
819 case LWAX: {
820 Format(instr, "lwax 'rt, 'ra, 'rb");
821 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822 }
823 case LBZX: {
824 Format(instr, "lbzx 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400826 }
827 case LBZUX: {
828 Format(instr, "lbzux 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400830 }
831 case LHZX: {
832 Format(instr, "lhzx 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000833 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400834 }
835 case LHZUX: {
836 Format(instr, "lhzux 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000837 return;
838 }
839 case LHAX: {
840 Format(instr, "lhax 'rt, 'ra, 'rb");
841 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400842 }
843#if V8_TARGET_ARCH_PPC64
844 case LDX: {
845 Format(instr, "ldx 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400847 }
848 case LDUX: {
849 Format(instr, "ldux 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000850 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400851 }
852 case STDX: {
853 Format(instr, "stdx 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000854 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400855 }
856 case STDUX: {
857 Format(instr, "stdux 'rt, 'ra, 'rb");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000858 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400859 }
860 case MFVSRD: {
861 Format(instr, "mffprd 'ra, 'Dt");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400863 }
864 case MFVSRWZ: {
865 Format(instr, "mffprwz 'ra, 'Dt");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400867 }
868 case MTVSRD: {
869 Format(instr, "mtfprd 'Dt, 'ra");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400871 }
872 case MTVSRWA: {
873 Format(instr, "mtfprwa 'Dt, 'ra");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000874 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400875 }
876 case MTVSRWZ: {
877 Format(instr, "mtfprwz 'Dt, 'ra");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000878 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400879 }
880#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 }
882
883 switch (instr->Bits(5, 1) << 1) {
884 case ISEL: {
885 Format(instr, "isel 'rt, 'ra, 'rb");
886 return;
887 }
888 default: {
889 Unknown(instr); // not used by V8
890 }
891 }
892}
893
894
895void Decoder::DecodeExt3(Instruction* instr) {
896 switch (instr->Bits(10, 1) << 1) {
897 case FCFID: {
898 Format(instr, "fcfids'. 'Dt, 'Db");
899 break;
900 }
901 case FCFIDU: {
902 Format(instr, "fcfidus'.'Dt, 'Db");
903 break;
904 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400905 default: {
906 Unknown(instr); // not used by V8
907 }
908 }
909}
910
911
912void Decoder::DecodeExt4(Instruction* instr) {
913 switch (instr->Bits(5, 1) << 1) {
914 case FDIV: {
915 Format(instr, "fdiv'. 'Dt, 'Da, 'Db");
916 return;
917 }
918 case FSUB: {
919 Format(instr, "fsub'. 'Dt, 'Da, 'Db");
920 return;
921 }
922 case FADD: {
923 Format(instr, "fadd'. 'Dt, 'Da, 'Db");
924 return;
925 }
926 case FSQRT: {
927 Format(instr, "fsqrt'. 'Dt, 'Db");
928 return;
929 }
930 case FSEL: {
931 Format(instr, "fsel'. 'Dt, 'Da, 'Dc, 'Db");
932 return;
933 }
934 case FMUL: {
935 Format(instr, "fmul'. 'Dt, 'Da, 'Dc");
936 return;
937 }
938 case FMSUB: {
939 Format(instr, "fmsub'. 'Dt, 'Da, 'Dc, 'Db");
940 return;
941 }
942 case FMADD: {
943 Format(instr, "fmadd'. 'Dt, 'Da, 'Dc, 'Db");
944 return;
945 }
946 }
947
948 switch (instr->Bits(10, 1) << 1) {
949 case FCMPU: {
950 Format(instr, "fcmpu 'Da, 'Db");
951 break;
952 }
953 case FRSP: {
954 Format(instr, "frsp'. 'Dt, 'Db");
955 break;
956 }
957 case FCFID: {
958 Format(instr, "fcfid'. 'Dt, 'Db");
959 break;
960 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000961 case FCFIDU: {
962 Format(instr, "fcfidu'. 'Dt, 'Db");
963 break;
964 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400965 case FCTID: {
966 Format(instr, "fctid 'Dt, 'Db");
967 break;
968 }
969 case FCTIDZ: {
970 Format(instr, "fctidz 'Dt, 'Db");
971 break;
972 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 case FCTIDU: {
974 Format(instr, "fctidu 'Dt, 'Db");
975 break;
976 }
977 case FCTIDUZ: {
978 Format(instr, "fctiduz 'Dt, 'Db");
979 break;
980 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400981 case FCTIW: {
982 Format(instr, "fctiw'. 'Dt, 'Db");
983 break;
984 }
985 case FCTIWZ: {
986 Format(instr, "fctiwz'. 'Dt, 'Db");
987 break;
988 }
989 case FMR: {
990 Format(instr, "fmr'. 'Dt, 'Db");
991 break;
992 }
993 case MTFSFI: {
994 Format(instr, "mtfsfi'. ?,?");
995 break;
996 }
997 case MFFS: {
998 Format(instr, "mffs'. 'Dt");
999 break;
1000 }
1001 case MTFSF: {
1002 Format(instr, "mtfsf'. 'Db ?,?,?");
1003 break;
1004 }
1005 case FABS: {
1006 Format(instr, "fabs'. 'Dt, 'Db");
1007 break;
1008 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001009 case FRIN: {
1010 Format(instr, "frin. 'Dt, 'Db");
1011 break;
1012 }
1013 case FRIZ: {
1014 Format(instr, "friz. 'Dt, 'Db");
1015 break;
1016 }
1017 case FRIP: {
1018 Format(instr, "frip. 'Dt, 'Db");
1019 break;
1020 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001021 case FRIM: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 Format(instr, "frim. 'Dt, 'Db");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001023 break;
1024 }
1025 case FNEG: {
1026 Format(instr, "fneg'. 'Dt, 'Db");
1027 break;
1028 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029 case MCRFS: {
1030 Format(instr, "mcrfs ?,?");
1031 break;
1032 }
1033 case MTFSB0: {
1034 Format(instr, "mtfsb0'. ?");
1035 break;
1036 }
1037 case MTFSB1: {
1038 Format(instr, "mtfsb1'. ?");
1039 break;
1040 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001041 default: {
1042 Unknown(instr); // not used by V8
1043 }
1044 }
1045}
1046
1047
1048void Decoder::DecodeExt5(Instruction* instr) {
1049 switch (instr->Bits(4, 2) << 2) {
1050 case RLDICL: {
1051 Format(instr, "rldicl'. 'ra, 'rs, 'sh, 'mb");
1052 return;
1053 }
1054 case RLDICR: {
1055 Format(instr, "rldicr'. 'ra, 'rs, 'sh, 'me");
1056 return;
1057 }
1058 case RLDIC: {
1059 Format(instr, "rldic'. 'ra, 'rs, 'sh, 'mb");
1060 return;
1061 }
1062 case RLDIMI: {
1063 Format(instr, "rldimi'. 'ra, 'rs, 'sh, 'mb");
1064 return;
1065 }
1066 }
1067 switch (instr->Bits(4, 1) << 1) {
1068 case RLDCL: {
1069 Format(instr, "rldcl'. 'ra, 'rs, 'sb, 'mb");
1070 return;
1071 }
1072 }
1073 Unknown(instr); // not used by V8
1074}
1075
1076#undef VERIFIY
1077
1078// Disassemble the instruction at *instr_ptr into the output buffer.
1079int Decoder::InstructionDecode(byte* instr_ptr) {
1080 Instruction* instr = Instruction::At(instr_ptr);
1081 // Print raw instruction bytes.
1082 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x ",
1083 instr->InstructionBits());
1084
Ben Murdoch097c5b22016-05-18 11:27:45 +01001085 if (ABI_USES_FUNCTION_DESCRIPTORS && instr->InstructionBits() == 0) {
1086 // The first field will be identified as a jump table entry. We
1087 // emit the rest of the structure as zero, so just skip past them.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001088 Format(instr, "constant");
1089 return Instruction::kInstrSize;
1090 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001092 switch (instr->OpcodeValue() << 26) {
1093 case TWI: {
1094 PrintSoftwareInterrupt(instr->SvcValue());
1095 break;
1096 }
1097 case MULLI: {
1098 UnknownFormat(instr, "mulli");
1099 break;
1100 }
1101 case SUBFIC: {
1102 Format(instr, "subfic 'rt, 'ra, 'int16");
1103 break;
1104 }
1105 case CMPLI: {
1106#if V8_TARGET_ARCH_PPC64
1107 if (instr->Bit(21)) {
1108#endif
1109 Format(instr, "cmpli 'ra, 'uint16");
1110#if V8_TARGET_ARCH_PPC64
1111 } else {
1112 Format(instr, "cmplwi 'ra, 'uint16");
1113 }
1114#endif
1115 break;
1116 }
1117 case CMPI: {
1118#if V8_TARGET_ARCH_PPC64
1119 if (instr->Bit(21)) {
1120#endif
1121 Format(instr, "cmpi 'ra, 'int16");
1122#if V8_TARGET_ARCH_PPC64
1123 } else {
1124 Format(instr, "cmpwi 'ra, 'int16");
1125 }
1126#endif
1127 break;
1128 }
1129 case ADDIC: {
1130 Format(instr, "addic 'rt, 'ra, 'int16");
1131 break;
1132 }
1133 case ADDICx: {
1134 UnknownFormat(instr, "addicx");
1135 break;
1136 }
1137 case ADDI: {
1138 if (instr->RAValue() == 0) {
1139 // this is load immediate
1140 Format(instr, "li 'rt, 'int16");
1141 } else {
1142 Format(instr, "addi 'rt, 'ra, 'int16");
1143 }
1144 break;
1145 }
1146 case ADDIS: {
1147 if (instr->RAValue() == 0) {
1148 Format(instr, "lis 'rt, 'int16");
1149 } else {
1150 Format(instr, "addis 'rt, 'ra, 'int16");
1151 }
1152 break;
1153 }
1154 case BCX: {
1155 int bo = instr->Bits(25, 21) << 21;
1156 int bi = instr->Bits(20, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 CRBit cond = static_cast<CRBit>(bi & (CRWIDTH - 1));
1158 switch (bo) {
1159 case BT: { // Branch if condition true
1160 switch (cond) {
1161 case CR_EQ:
1162 Format(instr, "beq'l'a'cr 'target16");
1163 break;
1164 case CR_GT:
1165 Format(instr, "bgt'l'a'cr 'target16");
1166 break;
1167 case CR_LT:
1168 Format(instr, "blt'l'a'cr 'target16");
1169 break;
1170 case CR_SO:
1171 Format(instr, "bso'l'a'cr 'target16");
1172 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001173 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001174 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001175 }
1176 case BF: { // Branch if condition false
1177 switch (cond) {
1178 case CR_EQ:
1179 Format(instr, "bne'l'a'cr 'target16");
1180 break;
1181 case CR_GT:
1182 Format(instr, "ble'l'a'cr 'target16");
1183 break;
1184 case CR_LT:
1185 Format(instr, "bge'l'a'cr 'target16");
1186 break;
1187 case CR_SO:
1188 Format(instr, "bnso'l'a'cr 'target16");
1189 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001190 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001191 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001192 }
1193 case DCBNZ: { // Decrement CTR; branch if CTR != 0
1194 Format(instr, "bdnz'l'a 'target16");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001195 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001196 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001197 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001198 Format(instr, "bc'l'a'cr 'target16");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001199 break;
1200 }
1201 break;
1202 }
1203 case SC: {
1204 UnknownFormat(instr, "sc");
1205 break;
1206 }
1207 case BX: {
1208 Format(instr, "b'l'a 'target26");
1209 break;
1210 }
1211 case EXT1: {
1212 DecodeExt1(instr);
1213 break;
1214 }
1215 case RLWIMIX: {
1216 Format(instr, "rlwimi'. 'ra, 'rs, 'sh, 'me, 'mb");
1217 break;
1218 }
1219 case RLWINMX: {
1220 Format(instr, "rlwinm'. 'ra, 'rs, 'sh, 'me, 'mb");
1221 break;
1222 }
1223 case RLWNMX: {
1224 Format(instr, "rlwnm'. 'ra, 'rs, 'rb, 'me, 'mb");
1225 break;
1226 }
1227 case ORI: {
1228 Format(instr, "ori 'ra, 'rs, 'uint16");
1229 break;
1230 }
1231 case ORIS: {
1232 Format(instr, "oris 'ra, 'rs, 'uint16");
1233 break;
1234 }
1235 case XORI: {
1236 Format(instr, "xori 'ra, 'rs, 'uint16");
1237 break;
1238 }
1239 case XORIS: {
1240 Format(instr, "xoris 'ra, 'rs, 'uint16");
1241 break;
1242 }
1243 case ANDIx: {
1244 Format(instr, "andi. 'ra, 'rs, 'uint16");
1245 break;
1246 }
1247 case ANDISx: {
1248 Format(instr, "andis. 'ra, 'rs, 'uint16");
1249 break;
1250 }
1251 case EXT2: {
1252 DecodeExt2(instr);
1253 break;
1254 }
1255 case LWZ: {
1256 Format(instr, "lwz 'rt, 'int16('ra)");
1257 break;
1258 }
1259 case LWZU: {
1260 Format(instr, "lwzu 'rt, 'int16('ra)");
1261 break;
1262 }
1263 case LBZ: {
1264 Format(instr, "lbz 'rt, 'int16('ra)");
1265 break;
1266 }
1267 case LBZU: {
1268 Format(instr, "lbzu 'rt, 'int16('ra)");
1269 break;
1270 }
1271 case STW: {
1272 Format(instr, "stw 'rs, 'int16('ra)");
1273 break;
1274 }
1275 case STWU: {
1276 Format(instr, "stwu 'rs, 'int16('ra)");
1277 break;
1278 }
1279 case STB: {
1280 Format(instr, "stb 'rs, 'int16('ra)");
1281 break;
1282 }
1283 case STBU: {
1284 Format(instr, "stbu 'rs, 'int16('ra)");
1285 break;
1286 }
1287 case LHZ: {
1288 Format(instr, "lhz 'rt, 'int16('ra)");
1289 break;
1290 }
1291 case LHZU: {
1292 Format(instr, "lhzu 'rt, 'int16('ra)");
1293 break;
1294 }
1295 case LHA: {
1296 Format(instr, "lha 'rt, 'int16('ra)");
1297 break;
1298 }
1299 case LHAU: {
1300 Format(instr, "lhau 'rt, 'int16('ra)");
1301 break;
1302 }
1303 case STH: {
1304 Format(instr, "sth 'rs, 'int16('ra)");
1305 break;
1306 }
1307 case STHU: {
1308 Format(instr, "sthu 'rs, 'int16('ra)");
1309 break;
1310 }
1311 case LMW: {
1312 UnknownFormat(instr, "lmw");
1313 break;
1314 }
1315 case STMW: {
1316 UnknownFormat(instr, "stmw");
1317 break;
1318 }
1319 case LFS: {
1320 Format(instr, "lfs 'Dt, 'int16('ra)");
1321 break;
1322 }
1323 case LFSU: {
1324 Format(instr, "lfsu 'Dt, 'int16('ra)");
1325 break;
1326 }
1327 case LFD: {
1328 Format(instr, "lfd 'Dt, 'int16('ra)");
1329 break;
1330 }
1331 case LFDU: {
1332 Format(instr, "lfdu 'Dt, 'int16('ra)");
1333 break;
1334 }
1335 case STFS: {
1336 Format(instr, "stfs 'Dt, 'int16('ra)");
1337 break;
1338 }
1339 case STFSU: {
1340 Format(instr, "stfsu 'Dt, 'int16('ra)");
1341 break;
1342 }
1343 case STFD: {
1344 Format(instr, "stfd 'Dt, 'int16('ra)");
1345 break;
1346 }
1347 case STFDU: {
1348 Format(instr, "stfdu 'Dt, 'int16('ra)");
1349 break;
1350 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 case EXT3: {
1352 DecodeExt3(instr);
1353 break;
1354 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001355 case EXT4: {
1356 DecodeExt4(instr);
1357 break;
1358 }
1359 case EXT5: {
1360 DecodeExt5(instr);
1361 break;
1362 }
1363#if V8_TARGET_ARCH_PPC64
1364 case LD: {
1365 switch (instr->Bits(1, 0)) {
1366 case 0:
1367 Format(instr, "ld 'rt, 'd('ra)");
1368 break;
1369 case 1:
1370 Format(instr, "ldu 'rt, 'd('ra)");
1371 break;
1372 case 2:
1373 Format(instr, "lwa 'rt, 'd('ra)");
1374 break;
1375 }
1376 break;
1377 }
1378 case STD: { // could be STD or STDU
1379 if (instr->Bit(0) == 0) {
1380 Format(instr, "std 'rs, 'd('ra)");
1381 } else {
1382 Format(instr, "stdu 'rs, 'd('ra)");
1383 }
1384 break;
1385 }
1386#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 default: {
1388 Unknown(instr);
1389 break;
1390 }
1391 }
1392
1393 return Instruction::kInstrSize;
1394}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395} // namespace internal
1396} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001397
1398
1399//------------------------------------------------------------------------------
1400
1401namespace disasm {
1402
1403
1404const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001405 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001406 return tmp_buffer_.start();
1407}
1408
1409
1410const char* NameConverter::NameOfConstant(byte* addr) const {
1411 return NameOfAddress(addr);
1412}
1413
1414
1415const char* NameConverter::NameOfCPURegister(int reg) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001416 return v8::internal::GetRegConfig()->GetGeneralRegisterName(reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001417}
1418
1419const char* NameConverter::NameOfByteCPURegister(int reg) const {
1420 UNREACHABLE(); // PPC does not have the concept of a byte register
1421 return "nobytereg";
1422}
1423
1424
1425const char* NameConverter::NameOfXMMRegister(int reg) const {
1426 UNREACHABLE(); // PPC does not have any XMM registers
1427 return "noxmmreg";
1428}
1429
1430const char* NameConverter::NameInCode(byte* addr) const {
1431 // The default name converter is called for unknown code. So we will not try
1432 // to access any memory.
1433 return "";
1434}
1435
1436
1437//------------------------------------------------------------------------------
1438
1439Disassembler::Disassembler(const NameConverter& converter)
1440 : converter_(converter) {}
1441
1442
1443Disassembler::~Disassembler() {}
1444
1445
1446int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1447 byte* instruction) {
1448 v8::internal::Decoder d(converter_, buffer);
1449 return d.InstructionDecode(instruction);
1450}
1451
1452
1453// The PPC assembler does not currently use constant pools.
1454int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1455
1456
1457void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1458 NameConverter converter;
1459 Disassembler d(converter);
1460 for (byte* pc = begin; pc < end;) {
1461 v8::internal::EmbeddedVector<char, 128> buffer;
1462 buffer[0] = '\0';
1463 byte* prev_pc = pc;
1464 pc += d.InstructionDecode(buffer, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001465 v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001466 *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1467 }
1468}
1469
1470
1471} // namespace disasm
1472
1473#endif // V8_TARGET_ARCH_PPC