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

Side by Side Diff: src/a64/disasm-a64.cc

Issue 144963003: A64: add missing files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/a64/disasm-a64.h ('k') | src/a64/frames-a64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #ifndef WIN32
33 #include <stdint.h>
34 #endif
35
36 #include "v8.h"
37
38 #if defined(V8_TARGET_ARCH_A64)
39
40 #include "disasm.h"
41 #include "a64/disasm-a64.h"
42 #include "macro-assembler.h"
43 #include "platform.h"
44
45 namespace v8 {
46 namespace internal {
47
48
49 Disassembler::Disassembler() {
50 buffer_size_ = 256;
51 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
52 buffer_pos_ = 0;
53 own_buffer_ = true;
54 }
55
56
57 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
58 buffer_size_ = buffer_size;
59 buffer_ = text_buffer;
60 buffer_pos_ = 0;
61 own_buffer_ = false;
62 }
63
64
65 Disassembler::~Disassembler() {
66 if (own_buffer_) {
67 free(buffer_);
68 }
69 }
70
71
72 char* Disassembler::GetOutput() {
73 return buffer_;
74 }
75
76
77 void Disassembler::VisitAddSubImmediate(Instruction* instr) {
78 bool rd_is_zr = RdIsZROrSP(instr);
79 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
80 (instr->ImmAddSub() == 0) ? true : false;
81 const char *mnemonic = "";
82 const char *form = "'Rds, 'Rns, 'IAddSub";
83 const char *form_cmp = "'Rns, 'IAddSub";
84 const char *form_mov = "'Rds, 'Rns";
85
86 switch (instr->Mask(AddSubImmediateMask)) {
87 case ADD_w_imm:
88 case ADD_x_imm: {
89 mnemonic = "add";
90 if (stack_op) {
91 mnemonic = "mov";
92 form = form_mov;
93 }
94 break;
95 }
96 case ADDS_w_imm:
97 case ADDS_x_imm: {
98 mnemonic = "adds";
99 if (rd_is_zr) {
100 mnemonic = "cmn";
101 form = form_cmp;
102 }
103 break;
104 }
105 case SUB_w_imm:
106 case SUB_x_imm: mnemonic = "sub"; break;
107 case SUBS_w_imm:
108 case SUBS_x_imm: {
109 mnemonic = "subs";
110 if (rd_is_zr) {
111 mnemonic = "cmp";
112 form = form_cmp;
113 }
114 break;
115 }
116 default: UNREACHABLE();
117 }
118 Format(instr, mnemonic, form);
119 }
120
121
122 void Disassembler::VisitAddSubShifted(Instruction* instr) {
123 bool rd_is_zr = RdIsZROrSP(instr);
124 bool rn_is_zr = RnIsZROrSP(instr);
125 const char *mnemonic = "";
126 const char *form = "'Rd, 'Rn, 'Rm'HDP";
127 const char *form_cmp = "'Rn, 'Rm'HDP";
128 const char *form_neg = "'Rd, 'Rm'HDP";
129
130 switch (instr->Mask(AddSubShiftedMask)) {
131 case ADD_w_shift:
132 case ADD_x_shift: mnemonic = "add"; break;
133 case ADDS_w_shift:
134 case ADDS_x_shift: {
135 mnemonic = "adds";
136 if (rd_is_zr) {
137 mnemonic = "cmn";
138 form = form_cmp;
139 }
140 break;
141 }
142 case SUB_w_shift:
143 case SUB_x_shift: {
144 mnemonic = "sub";
145 if (rn_is_zr) {
146 mnemonic = "neg";
147 form = form_neg;
148 }
149 break;
150 }
151 case SUBS_w_shift:
152 case SUBS_x_shift: {
153 mnemonic = "subs";
154 if (rd_is_zr) {
155 mnemonic = "cmp";
156 form = form_cmp;
157 } else if (rn_is_zr) {
158 mnemonic = "negs";
159 form = form_neg;
160 }
161 break;
162 }
163 default: UNREACHABLE();
164 }
165 Format(instr, mnemonic, form);
166 }
167
168
169 void Disassembler::VisitAddSubExtended(Instruction* instr) {
170 bool rd_is_zr = RdIsZROrSP(instr);
171 const char *mnemonic = "";
172 Extend mode = static_cast<Extend>(instr->ExtendMode());
173 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
174 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
175 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
176 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
177
178 switch (instr->Mask(AddSubExtendedMask)) {
179 case ADD_w_ext:
180 case ADD_x_ext: mnemonic = "add"; break;
181 case ADDS_w_ext:
182 case ADDS_x_ext: {
183 mnemonic = "adds";
184 if (rd_is_zr) {
185 mnemonic = "cmn";
186 form = form_cmp;
187 }
188 break;
189 }
190 case SUB_w_ext:
191 case SUB_x_ext: mnemonic = "sub"; break;
192 case SUBS_w_ext:
193 case SUBS_x_ext: {
194 mnemonic = "subs";
195 if (rd_is_zr) {
196 mnemonic = "cmp";
197 form = form_cmp;
198 }
199 break;
200 }
201 default: UNREACHABLE();
202 }
203 Format(instr, mnemonic, form);
204 }
205
206
207 void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
208 bool rn_is_zr = RnIsZROrSP(instr);
209 const char *mnemonic = "";
210 const char *form = "'Rd, 'Rn, 'Rm";
211 const char *form_neg = "'Rd, 'Rm";
212
213 switch (instr->Mask(AddSubWithCarryMask)) {
214 case ADC_w:
215 case ADC_x: mnemonic = "adc"; break;
216 case ADCS_w:
217 case ADCS_x: mnemonic = "adcs"; break;
218 case SBC_w:
219 case SBC_x: {
220 mnemonic = "sbc";
221 if (rn_is_zr) {
222 mnemonic = "ngc";
223 form = form_neg;
224 }
225 break;
226 }
227 case SBCS_w:
228 case SBCS_x: {
229 mnemonic = "sbcs";
230 if (rn_is_zr) {
231 mnemonic = "ngcs";
232 form = form_neg;
233 }
234 break;
235 }
236 default: UNREACHABLE();
237 }
238 Format(instr, mnemonic, form);
239 }
240
241
242 void Disassembler::VisitLogicalImmediate(Instruction* instr) {
243 bool rd_is_zr = RdIsZROrSP(instr);
244 bool rn_is_zr = RnIsZROrSP(instr);
245 const char *mnemonic = "";
246 const char *form = "'Rds, 'Rn, 'ITri";
247
248 if (instr->ImmLogical() == 0) {
249 // The immediate encoded in the instruction is not in the expected format.
250 Format(instr, "unallocated", "(LogicalImmediate)");
251 return;
252 }
253
254 switch (instr->Mask(LogicalImmediateMask)) {
255 case AND_w_imm:
256 case AND_x_imm: mnemonic = "and"; break;
257 case ORR_w_imm:
258 case ORR_x_imm: {
259 mnemonic = "orr";
260 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
261 : kWRegSize;
262 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
263 mnemonic = "mov";
264 form = "'Rds, 'ITri";
265 }
266 break;
267 }
268 case EOR_w_imm:
269 case EOR_x_imm: mnemonic = "eor"; break;
270 case ANDS_w_imm:
271 case ANDS_x_imm: {
272 mnemonic = "ands";
273 if (rd_is_zr) {
274 mnemonic = "tst";
275 form = "'Rn, 'ITri";
276 }
277 break;
278 }
279 default: UNREACHABLE();
280 }
281 Format(instr, mnemonic, form);
282 }
283
284
285 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
286 ASSERT((reg_size == kXRegSize) ||
287 ((reg_size == kWRegSize) && (value <= 0xffffffff)));
288
289 // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
290 if (((value & 0xffffffffffff0000UL) == 0UL) ||
291 ((value & 0xffffffff0000ffffUL) == 0UL) ||
292 ((value & 0xffff0000ffffffffUL) == 0UL) ||
293 ((value & 0x0000ffffffffffffUL) == 0UL)) {
294 return true;
295 }
296
297 // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
298 if ((reg_size == kXRegSize) &&
299 (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
300 ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
301 ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
302 ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
303 return true;
304 }
305 if ((reg_size == kWRegSize) &&
306 (((value & 0xffff0000) == 0xffff0000) ||
307 ((value & 0x0000ffff) == 0x0000ffff))) {
308 return true;
309 }
310 return false;
311 }
312
313
314 void Disassembler::VisitLogicalShifted(Instruction* instr) {
315 bool rd_is_zr = RdIsZROrSP(instr);
316 bool rn_is_zr = RnIsZROrSP(instr);
317 const char *mnemonic = "";
318 const char *form = "'Rd, 'Rn, 'Rm'HLo";
319
320 switch (instr->Mask(LogicalShiftedMask)) {
321 case AND_w:
322 case AND_x: mnemonic = "and"; break;
323 case BIC_w:
324 case BIC_x: mnemonic = "bic"; break;
325 case EOR_w:
326 case EOR_x: mnemonic = "eor"; break;
327 case EON_w:
328 case EON_x: mnemonic = "eon"; break;
329 case BICS_w:
330 case BICS_x: mnemonic = "bics"; break;
331 case ANDS_w:
332 case ANDS_x: {
333 mnemonic = "ands";
334 if (rd_is_zr) {
335 mnemonic = "tst";
336 form = "'Rn, 'Rm'HLo";
337 }
338 break;
339 }
340 case ORR_w:
341 case ORR_x: {
342 mnemonic = "orr";
343 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
344 mnemonic = "mov";
345 form = "'Rd, 'Rm";
346 }
347 break;
348 }
349 case ORN_w:
350 case ORN_x: {
351 mnemonic = "orn";
352 if (rn_is_zr) {
353 mnemonic = "mvn";
354 form = "'Rd, 'Rm'HLo";
355 }
356 break;
357 }
358 default: UNREACHABLE();
359 }
360
361 Format(instr, mnemonic, form);
362 }
363
364
365 void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
366 const char *mnemonic = "";
367 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
368
369 switch (instr->Mask(ConditionalCompareRegisterMask)) {
370 case CCMN_w:
371 case CCMN_x: mnemonic = "ccmn"; break;
372 case CCMP_w:
373 case CCMP_x: mnemonic = "ccmp"; break;
374 default: UNREACHABLE();
375 }
376 Format(instr, mnemonic, form);
377 }
378
379
380 void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
381 const char *mnemonic = "";
382 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
383
384 switch (instr->Mask(ConditionalCompareImmediateMask)) {
385 case CCMN_w_imm:
386 case CCMN_x_imm: mnemonic = "ccmn"; break;
387 case CCMP_w_imm:
388 case CCMP_x_imm: mnemonic = "ccmp"; break;
389 default: UNREACHABLE();
390 }
391 Format(instr, mnemonic, form);
392 }
393
394
395 void Disassembler::VisitConditionalSelect(Instruction* instr) {
396 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
397 bool rn_is_rm = (instr->Rn() == instr->Rm());
398 const char *mnemonic = "";
399 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
400 const char *form_test = "'Rd, 'CInv";
401 const char *form_update = "'Rd, 'Rn, 'CInv";
402
403 Condition cond = static_cast<Condition>(instr->Condition());
404 bool invertible_cond = (cond != al) && (cond != nv);
405
406 switch (instr->Mask(ConditionalSelectMask)) {
407 case CSEL_w:
408 case CSEL_x: mnemonic = "csel"; break;
409 case CSINC_w:
410 case CSINC_x: {
411 mnemonic = "csinc";
412 if (rnm_is_zr && invertible_cond) {
413 mnemonic = "cset";
414 form = form_test;
415 } else if (rn_is_rm && invertible_cond) {
416 mnemonic = "cinc";
417 form = form_update;
418 }
419 break;
420 }
421 case CSINV_w:
422 case CSINV_x: {
423 mnemonic = "csinv";
424 if (rnm_is_zr && invertible_cond) {
425 mnemonic = "csetm";
426 form = form_test;
427 } else if (rn_is_rm && invertible_cond) {
428 mnemonic = "cinv";
429 form = form_update;
430 }
431 break;
432 }
433 case CSNEG_w:
434 case CSNEG_x: {
435 mnemonic = "csneg";
436 if (rn_is_rm && invertible_cond) {
437 mnemonic = "cneg";
438 form = form_update;
439 }
440 break;
441 }
442 default: UNREACHABLE();
443 }
444 Format(instr, mnemonic, form);
445 }
446
447
448 void Disassembler::VisitBitfield(Instruction* instr) {
449 unsigned s = instr->ImmS();
450 unsigned r = instr->ImmR();
451 unsigned rd_size_minus_1 =
452 ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
453 const char *mnemonic = "";
454 const char *form = "";
455 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
456 const char *form_extend = "'Rd, 'Wn";
457 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
458 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
459 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
460
461 switch (instr->Mask(BitfieldMask)) {
462 case SBFM_w:
463 case SBFM_x: {
464 mnemonic = "sbfx";
465 form = form_bfx;
466 if (r == 0) {
467 form = form_extend;
468 if (s == 7) {
469 mnemonic = "sxtb";
470 } else if (s == 15) {
471 mnemonic = "sxth";
472 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
473 mnemonic = "sxtw";
474 } else {
475 form = form_bfx;
476 }
477 } else if (s == rd_size_minus_1) {
478 mnemonic = "asr";
479 form = form_shift_right;
480 } else if (s < r) {
481 mnemonic = "sbfiz";
482 form = form_bfiz;
483 }
484 break;
485 }
486 case UBFM_w:
487 case UBFM_x: {
488 mnemonic = "ubfx";
489 form = form_bfx;
490 if (r == 0) {
491 form = form_extend;
492 if (s == 7) {
493 mnemonic = "uxtb";
494 } else if (s == 15) {
495 mnemonic = "uxth";
496 } else {
497 form = form_bfx;
498 }
499 }
500 if (s == rd_size_minus_1) {
501 mnemonic = "lsr";
502 form = form_shift_right;
503 } else if (r == s + 1) {
504 mnemonic = "lsl";
505 form = form_lsl;
506 } else if (s < r) {
507 mnemonic = "ubfiz";
508 form = form_bfiz;
509 }
510 break;
511 }
512 case BFM_w:
513 case BFM_x: {
514 mnemonic = "bfxil";
515 form = form_bfx;
516 if (s < r) {
517 mnemonic = "bfi";
518 form = form_bfiz;
519 }
520 }
521 }
522 Format(instr, mnemonic, form);
523 }
524
525
526 void Disassembler::VisitExtract(Instruction* instr) {
527 const char *mnemonic = "";
528 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
529
530 switch (instr->Mask(ExtractMask)) {
531 case EXTR_w:
532 case EXTR_x: {
533 if (instr->Rn() == instr->Rm()) {
534 mnemonic = "ror";
535 form = "'Rd, 'Rn, 'IExtract";
536 } else {
537 mnemonic = "extr";
538 }
539 break;
540 }
541 default: UNREACHABLE();
542 }
543 Format(instr, mnemonic, form);
544 }
545
546
547 void Disassembler::VisitPCRelAddressing(Instruction* instr) {
548 switch (instr->Mask(PCRelAddressingMask)) {
549 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
550 // ADRP is not implemented.
551 default: Format(instr, "unimplemented", "(PCRelAddressing)");
552 }
553 }
554
555
556 void Disassembler::VisitConditionalBranch(Instruction* instr) {
557 switch (instr->Mask(ConditionalBranchMask)) {
558 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
559 default: UNREACHABLE();
560 }
561 }
562
563
564 void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
565 const char *mnemonic = "unimplemented";
566 const char *form = "'Xn";
567
568 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
569 case BR: mnemonic = "br"; break;
570 case BLR: mnemonic = "blr"; break;
571 case RET: {
572 mnemonic = "ret";
573 if (instr->Rn() == kLinkRegCode) {
574 form = NULL;
575 }
576 break;
577 }
578 default: form = "(UnconditionalBranchToRegister)";
579 }
580 Format(instr, mnemonic, form);
581 }
582
583
584 void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
585 const char *mnemonic = "";
586 const char *form = "'BImmUncn";
587
588 switch (instr->Mask(UnconditionalBranchMask)) {
589 case B: mnemonic = "b"; break;
590 case BL: mnemonic = "bl"; break;
591 default: UNREACHABLE();
592 }
593 Format(instr, mnemonic, form);
594 }
595
596
597 void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
598 const char *mnemonic = "";
599 const char *form = "'Rd, 'Rn";
600
601 switch (instr->Mask(DataProcessing1SourceMask)) {
602 #define FORMAT(A, B) \
603 case A##_w: \
604 case A##_x: mnemonic = B; break;
605 FORMAT(RBIT, "rbit");
606 FORMAT(REV16, "rev16");
607 FORMAT(REV, "rev");
608 FORMAT(CLZ, "clz");
609 FORMAT(CLS, "cls");
610 #undef FORMAT
611 case REV32_x: mnemonic = "rev32"; break;
612 default: UNREACHABLE();
613 }
614 Format(instr, mnemonic, form);
615 }
616
617
618 void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
619 const char *mnemonic = "unimplemented";
620 const char *form = "'Rd, 'Rn, 'Rm";
621
622 switch (instr->Mask(DataProcessing2SourceMask)) {
623 #define FORMAT(A, B) \
624 case A##_w: \
625 case A##_x: mnemonic = B; break;
626 FORMAT(UDIV, "udiv");
627 FORMAT(SDIV, "sdiv");
628 FORMAT(LSLV, "lsl");
629 FORMAT(LSRV, "lsr");
630 FORMAT(ASRV, "asr");
631 FORMAT(RORV, "ror");
632 #undef FORMAT
633 default: form = "(DataProcessing2Source)";
634 }
635 Format(instr, mnemonic, form);
636 }
637
638
639 void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
640 bool ra_is_zr = RaIsZROrSP(instr);
641 const char *mnemonic = "";
642 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
643 const char *form_rrr = "'Rd, 'Rn, 'Rm";
644 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
645 const char *form_xww = "'Xd, 'Wn, 'Wm";
646 const char *form_xxx = "'Xd, 'Xn, 'Xm";
647
648 switch (instr->Mask(DataProcessing3SourceMask)) {
649 case MADD_w:
650 case MADD_x: {
651 mnemonic = "madd";
652 form = form_rrrr;
653 if (ra_is_zr) {
654 mnemonic = "mul";
655 form = form_rrr;
656 }
657 break;
658 }
659 case MSUB_w:
660 case MSUB_x: {
661 mnemonic = "msub";
662 form = form_rrrr;
663 if (ra_is_zr) {
664 mnemonic = "mneg";
665 form = form_rrr;
666 }
667 break;
668 }
669 case SMADDL_x: {
670 mnemonic = "smaddl";
671 if (ra_is_zr) {
672 mnemonic = "smull";
673 form = form_xww;
674 }
675 break;
676 }
677 case SMSUBL_x: {
678 mnemonic = "smsubl";
679 if (ra_is_zr) {
680 mnemonic = "smnegl";
681 form = form_xww;
682 }
683 break;
684 }
685 case UMADDL_x: {
686 mnemonic = "umaddl";
687 if (ra_is_zr) {
688 mnemonic = "umull";
689 form = form_xww;
690 }
691 break;
692 }
693 case UMSUBL_x: {
694 mnemonic = "umsubl";
695 if (ra_is_zr) {
696 mnemonic = "umnegl";
697 form = form_xww;
698 }
699 break;
700 }
701 case SMULH_x: {
702 mnemonic = "smulh";
703 form = form_xxx;
704 break;
705 }
706 case UMULH_x: {
707 mnemonic = "umulh";
708 form = form_xxx;
709 break;
710 }
711 default: UNREACHABLE();
712 }
713 Format(instr, mnemonic, form);
714 }
715
716
717 void Disassembler::VisitCompareBranch(Instruction* instr) {
718 const char *mnemonic = "";
719 const char *form = "'Rt, 'BImmCmpa";
720
721 switch (instr->Mask(CompareBranchMask)) {
722 case CBZ_w:
723 case CBZ_x: mnemonic = "cbz"; break;
724 case CBNZ_w:
725 case CBNZ_x: mnemonic = "cbnz"; break;
726 default: UNREACHABLE();
727 }
728 Format(instr, mnemonic, form);
729 }
730
731
732 void Disassembler::VisitTestBranch(Instruction* instr) {
733 const char *mnemonic = "";
734 // If the top bit of the immediate is clear, the tested register is
735 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
736 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
737 // uses bit 31 (normally "sf") to choose the register size.
738 const char *form = "'Rt, 'IS, 'BImmTest";
739
740 switch (instr->Mask(TestBranchMask)) {
741 case TBZ: mnemonic = "tbz"; break;
742 case TBNZ: mnemonic = "tbnz"; break;
743 default: UNREACHABLE();
744 }
745 Format(instr, mnemonic, form);
746 }
747
748
749 void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
750 const char *mnemonic = "";
751 const char *form = "'Rd, 'IMoveImm";
752
753 // Print the shift separately for movk, to make it clear which half word will
754 // be overwritten. Movn and movz print the computed immediate, which includes
755 // shift calculation.
756 switch (instr->Mask(MoveWideImmediateMask)) {
757 case MOVN_w:
758 case MOVN_x: mnemonic = "movn"; break;
759 case MOVZ_w:
760 case MOVZ_x: mnemonic = "movz"; break;
761 case MOVK_w:
762 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
763 default: UNREACHABLE();
764 }
765 Format(instr, mnemonic, form);
766 }
767
768
769 #define LOAD_STORE_LIST(V) \
770 V(STRB_w, "strb", "'Wt") \
771 V(STRH_w, "strh", "'Wt") \
772 V(STR_w, "str", "'Wt") \
773 V(STR_x, "str", "'Xt") \
774 V(LDRB_w, "ldrb", "'Wt") \
775 V(LDRH_w, "ldrh", "'Wt") \
776 V(LDR_w, "ldr", "'Wt") \
777 V(LDR_x, "ldr", "'Xt") \
778 V(LDRSB_x, "ldrsb", "'Xt") \
779 V(LDRSH_x, "ldrsh", "'Xt") \
780 V(LDRSW_x, "ldrsw", "'Xt") \
781 V(LDRSB_w, "ldrsb", "'Wt") \
782 V(LDRSH_w, "ldrsh", "'Wt") \
783 V(STR_s, "str", "'St") \
784 V(STR_d, "str", "'Dt") \
785 V(LDR_s, "ldr", "'St") \
786 V(LDR_d, "ldr", "'Dt")
787
788 void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
789 const char *mnemonic = "unimplemented";
790 const char *form = "(LoadStorePreIndex)";
791
792 switch (instr->Mask(LoadStorePreIndexMask)) {
793 #define LS_PREINDEX(A, B, C) \
794 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
795 LOAD_STORE_LIST(LS_PREINDEX)
796 #undef LS_PREINDEX
797 }
798 Format(instr, mnemonic, form);
799 }
800
801
802 void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
803 const char *mnemonic = "unimplemented";
804 const char *form = "(LoadStorePostIndex)";
805
806 switch (instr->Mask(LoadStorePostIndexMask)) {
807 #define LS_POSTINDEX(A, B, C) \
808 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
809 LOAD_STORE_LIST(LS_POSTINDEX)
810 #undef LS_POSTINDEX
811 }
812 Format(instr, mnemonic, form);
813 }
814
815
816 void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
817 const char *mnemonic = "unimplemented";
818 const char *form = "(LoadStoreUnsignedOffset)";
819
820 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
821 #define LS_UNSIGNEDOFFSET(A, B, C) \
822 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
823 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
824 #undef LS_UNSIGNEDOFFSET
825 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
826 }
827 Format(instr, mnemonic, form);
828 }
829
830
831 void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
832 const char *mnemonic = "unimplemented";
833 const char *form = "(LoadStoreRegisterOffset)";
834
835 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
836 #define LS_REGISTEROFFSET(A, B, C) \
837 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
838 LOAD_STORE_LIST(LS_REGISTEROFFSET)
839 #undef LS_REGISTEROFFSET
840 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
841 }
842 Format(instr, mnemonic, form);
843 }
844
845
846 void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
847 const char *mnemonic = "unimplemented";
848 const char *form = "'Wt, ['Xns'ILS]";
849 const char *form_x = "'Xt, ['Xns'ILS]";
850 const char *form_s = "'St, ['Xns'ILS]";
851 const char *form_d = "'Dt, ['Xns'ILS]";
852
853 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
854 case STURB_w: mnemonic = "sturb"; break;
855 case STURH_w: mnemonic = "sturh"; break;
856 case STUR_w: mnemonic = "stur"; break;
857 case STUR_x: mnemonic = "stur"; form = form_x; break;
858 case STUR_s: mnemonic = "stur"; form = form_s; break;
859 case STUR_d: mnemonic = "stur"; form = form_d; break;
860 case LDURB_w: mnemonic = "ldurb"; break;
861 case LDURH_w: mnemonic = "ldurh"; break;
862 case LDUR_w: mnemonic = "ldur"; break;
863 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
864 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
865 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
866 case LDURSB_x: form = form_x; // Fall through.
867 case LDURSB_w: mnemonic = "ldursb"; break;
868 case LDURSH_x: form = form_x; // Fall through.
869 case LDURSH_w: mnemonic = "ldursh"; break;
870 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
871 default: form = "(LoadStoreUnscaledOffset)";
872 }
873 Format(instr, mnemonic, form);
874 }
875
876
877 void Disassembler::VisitLoadLiteral(Instruction* instr) {
878 const char *mnemonic = "ldr";
879 const char *form = "(LoadLiteral)";
880
881 switch (instr->Mask(LoadLiteralMask)) {
882 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
883 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
884 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
885 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
886 default: mnemonic = "unimplemented";
887 }
888 Format(instr, mnemonic, form);
889 }
890
891
892 #define LOAD_STORE_PAIR_LIST(V) \
893 V(STP_w, "stp", "'Wt, 'Wt2", "4") \
894 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
895 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
896 V(STP_x, "stp", "'Xt, 'Xt2", "8") \
897 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
898 V(STP_s, "stp", "'St, 'St2", "4") \
899 V(LDP_s, "ldp", "'St, 'St2", "4") \
900 V(STP_d, "stp", "'Dt, 'Dt2", "8") \
901 V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
902
903 void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
904 const char *mnemonic = "unimplemented";
905 const char *form = "(LoadStorePairPostIndex)";
906
907 switch (instr->Mask(LoadStorePairPostIndexMask)) {
908 #define LSP_POSTINDEX(A, B, C, D) \
909 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
910 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
911 #undef LSP_POSTINDEX
912 }
913 Format(instr, mnemonic, form);
914 }
915
916
917 void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
918 const char *mnemonic = "unimplemented";
919 const char *form = "(LoadStorePairPreIndex)";
920
921 switch (instr->Mask(LoadStorePairPreIndexMask)) {
922 #define LSP_PREINDEX(A, B, C, D) \
923 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
924 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
925 #undef LSP_PREINDEX
926 }
927 Format(instr, mnemonic, form);
928 }
929
930
931 void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
932 const char *mnemonic = "unimplemented";
933 const char *form = "(LoadStorePairOffset)";
934
935 switch (instr->Mask(LoadStorePairOffsetMask)) {
936 #define LSP_OFFSET(A, B, C, D) \
937 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
938 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
939 #undef LSP_OFFSET
940 }
941 Format(instr, mnemonic, form);
942 }
943
944
945 void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
946 const char *mnemonic = "unimplemented";
947 const char *form;
948
949 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
950 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
951 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
952 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
953 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
954 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
955 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
956 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
957 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
958 default: form = "(LoadStorePairNonTemporal)";
959 }
960 Format(instr, mnemonic, form);
961 }
962
963
964 void Disassembler::VisitFPCompare(Instruction* instr) {
965 const char *mnemonic = "unimplemented";
966 const char *form = "'Fn, 'Fm";
967 const char *form_zero = "'Fn, #0.0";
968
969 switch (instr->Mask(FPCompareMask)) {
970 case FCMP_s_zero:
971 case FCMP_d_zero: form = form_zero; // Fall through.
972 case FCMP_s:
973 case FCMP_d: mnemonic = "fcmp"; break;
974 default: form = "(FPCompare)";
975 }
976 Format(instr, mnemonic, form);
977 }
978
979
980 void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
981 const char *mnemonic = "unimplemented";
982 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
983
984 switch (instr->Mask(FPConditionalCompareMask)) {
985 case FCCMP_s:
986 case FCCMP_d: mnemonic = "fccmp"; break;
987 case FCCMPE_s:
988 case FCCMPE_d: mnemonic = "fccmpe"; break;
989 default: form = "(FPConditionalCompare)";
990 }
991 Format(instr, mnemonic, form);
992 }
993
994
995 void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
996 const char *mnemonic = "";
997 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
998
999 switch (instr->Mask(FPConditionalSelectMask)) {
1000 case FCSEL_s:
1001 case FCSEL_d: mnemonic = "fcsel"; break;
1002 default: UNREACHABLE();
1003 }
1004 Format(instr, mnemonic, form);
1005 }
1006
1007
1008 void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
1009 const char *mnemonic = "unimplemented";
1010 const char *form = "'Fd, 'Fn";
1011
1012 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1013 #define FORMAT(A, B) \
1014 case A##_s: \
1015 case A##_d: mnemonic = B; break;
1016 FORMAT(FMOV, "fmov");
1017 FORMAT(FABS, "fabs");
1018 FORMAT(FNEG, "fneg");
1019 FORMAT(FSQRT, "fsqrt");
1020 FORMAT(FRINTN, "frintn");
1021 FORMAT(FRINTP, "frintp");
1022 FORMAT(FRINTM, "frintm");
1023 FORMAT(FRINTZ, "frintz");
1024 FORMAT(FRINTA, "frinta");
1025 FORMAT(FRINTX, "frintx");
1026 FORMAT(FRINTI, "frinti");
1027 #undef FORMAT
1028 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1029 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1030 default: form = "(FPDataProcessing1Source)";
1031 }
1032 Format(instr, mnemonic, form);
1033 }
1034
1035
1036 void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
1037 const char *mnemonic = "";
1038 const char *form = "'Fd, 'Fn, 'Fm";
1039
1040 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1041 #define FORMAT(A, B) \
1042 case A##_s: \
1043 case A##_d: mnemonic = B; break;
1044 FORMAT(FMUL, "fmul");
1045 FORMAT(FDIV, "fdiv");
1046 FORMAT(FADD, "fadd");
1047 FORMAT(FSUB, "fsub");
1048 FORMAT(FMAX, "fmax");
1049 FORMAT(FMIN, "fmin");
1050 FORMAT(FMAXNM, "fmaxnm");
1051 FORMAT(FMINNM, "fminnm");
1052 FORMAT(FNMUL, "fnmul");
1053 #undef FORMAT
1054 default: UNREACHABLE();
1055 }
1056 Format(instr, mnemonic, form);
1057 }
1058
1059
1060 void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
1061 const char *mnemonic = "";
1062 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1063
1064 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1065 #define FORMAT(A, B) \
1066 case A##_s: \
1067 case A##_d: mnemonic = B; break;
1068 FORMAT(FMADD, "fmadd");
1069 FORMAT(FMSUB, "fmsub");
1070 FORMAT(FNMADD, "fnmadd");
1071 FORMAT(FNMSUB, "fnmsub");
1072 #undef FORMAT
1073 default: UNREACHABLE();
1074 }
1075 Format(instr, mnemonic, form);
1076 }
1077
1078
1079 void Disassembler::VisitFPImmediate(Instruction* instr) {
1080 const char *mnemonic = "";
1081 const char *form = "(FPImmediate)";
1082
1083 switch (instr->Mask(FPImmediateMask)) {
1084 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1085 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1086 default: UNREACHABLE();
1087 }
1088 Format(instr, mnemonic, form);
1089 }
1090
1091
1092 void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
1093 const char *mnemonic = "unimplemented";
1094 const char *form = "(FPIntegerConvert)";
1095 const char *form_rf = "'Rd, 'Fn";
1096 const char *form_fr = "'Fd, 'Rn";
1097
1098 switch (instr->Mask(FPIntegerConvertMask)) {
1099 case FMOV_ws:
1100 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1101 case FMOV_sw:
1102 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1103 case FCVTAS_ws:
1104 case FCVTAS_xs:
1105 case FCVTAS_wd:
1106 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1107 case FCVTAU_ws:
1108 case FCVTAU_xs:
1109 case FCVTAU_wd:
1110 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1111 case FCVTMS_ws:
1112 case FCVTMS_xs:
1113 case FCVTMS_wd:
1114 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1115 case FCVTMU_ws:
1116 case FCVTMU_xs:
1117 case FCVTMU_wd:
1118 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1119 case FCVTNS_ws:
1120 case FCVTNS_xs:
1121 case FCVTNS_wd:
1122 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1123 case FCVTNU_ws:
1124 case FCVTNU_xs:
1125 case FCVTNU_wd:
1126 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1127 case FCVTZU_xd:
1128 case FCVTZU_ws:
1129 case FCVTZU_wd:
1130 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1131 case FCVTZS_xd:
1132 case FCVTZS_wd:
1133 case FCVTZS_xs:
1134 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1135 case SCVTF_sw:
1136 case SCVTF_sx:
1137 case SCVTF_dw:
1138 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1139 case UCVTF_sw:
1140 case UCVTF_sx:
1141 case UCVTF_dw:
1142 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1143 }
1144 Format(instr, mnemonic, form);
1145 }
1146
1147
1148 void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
1149 const char *mnemonic = "";
1150 const char *form = "'Rd, 'Fn, 'IFPFBits";
1151 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1152
1153 switch (instr->Mask(FPFixedPointConvertMask)) {
1154 case FCVTZS_ws_fixed:
1155 case FCVTZS_xs_fixed:
1156 case FCVTZS_wd_fixed:
1157 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1158 case FCVTZU_ws_fixed:
1159 case FCVTZU_xs_fixed:
1160 case FCVTZU_wd_fixed:
1161 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1162 case SCVTF_sw_fixed:
1163 case SCVTF_sx_fixed:
1164 case SCVTF_dw_fixed:
1165 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1166 case UCVTF_sw_fixed:
1167 case UCVTF_sx_fixed:
1168 case UCVTF_dw_fixed:
1169 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1170 }
1171 Format(instr, mnemonic, form);
1172 }
1173
1174
1175 void Disassembler::VisitSystem(Instruction* instr) {
1176 // Some system instructions hijack their Op and Cp fields to represent a
1177 // range of immediates instead of indicating a different instruction. This
1178 // makes the decoding tricky.
1179 const char *mnemonic = "unimplemented";
1180 const char *form = "(System)";
1181
1182 if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1183 switch (instr->Mask(SystemSysRegMask)) {
1184 case MRS: {
1185 mnemonic = "mrs";
1186 switch (instr->ImmSystemRegister()) {
1187 case NZCV: form = "'Xt, nzcv"; break;
1188 case FPCR: form = "'Xt, fpcr"; break;
1189 default: form = "'Xt, (unknown)"; break;
1190 }
1191 break;
1192 }
1193 case MSR: {
1194 mnemonic = "msr";
1195 switch (instr->ImmSystemRegister()) {
1196 case NZCV: form = "nzcv, 'Xt"; break;
1197 case FPCR: form = "fpcr, 'Xt"; break;
1198 default: form = "(unknown), 'Xt"; break;
1199 }
1200 break;
1201 }
1202 }
1203 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1204 ASSERT(instr->Mask(SystemHintMask) == HINT);
1205 switch (instr->ImmHint()) {
1206 case NOP: {
1207 mnemonic = "nop";
1208 form = NULL;
1209 break;
1210 }
1211 }
1212 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1213 switch (instr->Mask(MemBarrierMask)) {
1214 case DMB: {
1215 mnemonic = "dmb";
1216 form = "'M";
1217 break;
1218 }
1219 case DSB: {
1220 mnemonic = "dsb";
1221 form = "'M";
1222 break;
1223 }
1224 case ISB: {
1225 mnemonic = "isb";
1226 form = NULL;
1227 break;
1228 }
1229 }
1230 }
1231
1232 Format(instr, mnemonic, form);
1233 }
1234
1235
1236 void Disassembler::VisitException(Instruction* instr) {
1237 const char *mnemonic = "unimplemented";
1238 const char *form = "'IDebug";
1239
1240 switch (instr->Mask(ExceptionMask)) {
1241 case HLT: mnemonic = "hlt"; break;
1242 case BRK: mnemonic = "brk"; break;
1243 case SVC: mnemonic = "svc"; break;
1244 case HVC: mnemonic = "hvc"; break;
1245 case SMC: mnemonic = "smc"; break;
1246 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1247 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1248 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1249 default: form = "(Exception)";
1250 }
1251 Format(instr, mnemonic, form);
1252 }
1253
1254
1255 void Disassembler::VisitUnimplemented(Instruction* instr) {
1256 Format(instr, "unimplemented", "(Unimplemented)");
1257 }
1258
1259
1260 void Disassembler::VisitUnallocated(Instruction* instr) {
1261 Format(instr, "unallocated", "(Unallocated)");
1262 }
1263
1264
1265 void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1266 // The base disasm does nothing more than disassembling into a buffer.
1267 }
1268
1269
1270 void Disassembler::Format(Instruction* instr, const char* mnemonic,
1271 const char* format) {
1272 // TODO(mcapewel) don't think I can use the instr address here - there needs
1273 // to be a base address too
1274 ASSERT(mnemonic != NULL);
1275 ResetOutput();
1276 Substitute(instr, mnemonic);
1277 if (format != NULL) {
1278 buffer_[buffer_pos_++] = ' ';
1279 Substitute(instr, format);
1280 }
1281 buffer_[buffer_pos_] = 0;
1282 ProcessOutput(instr);
1283 }
1284
1285
1286 void Disassembler::Substitute(Instruction* instr, const char* string) {
1287 char chr = *string++;
1288 while (chr != '\0') {
1289 if (chr == '\'') {
1290 string += SubstituteField(instr, string);
1291 } else {
1292 buffer_[buffer_pos_++] = chr;
1293 }
1294 chr = *string++;
1295 }
1296 }
1297
1298
1299 int Disassembler::SubstituteField(Instruction* instr, const char* format) {
1300 switch (format[0]) {
1301 case 'R': // Register. X or W, selected by sf bit.
1302 case 'F': // FP Register. S or D, selected by type field.
1303 case 'W':
1304 case 'X':
1305 case 'S':
1306 case 'D': return SubstituteRegisterField(instr, format);
1307 case 'I': return SubstituteImmediateField(instr, format);
1308 case 'L': return SubstituteLiteralField(instr, format);
1309 case 'H': return SubstituteShiftField(instr, format);
1310 case 'P': return SubstitutePrefetchField(instr, format);
1311 case 'C': return SubstituteConditionField(instr, format);
1312 case 'E': return SubstituteExtendField(instr, format);
1313 case 'A': return SubstitutePCRelAddressField(instr, format);
1314 case 'B': return SubstituteBranchTargetField(instr, format);
1315 case 'O': return SubstituteLSRegOffsetField(instr, format);
1316 case 'M': return SubstituteBarrierField(instr, format);
1317 default: {
1318 UNREACHABLE();
1319 return 1;
1320 }
1321 }
1322 }
1323
1324
1325 int Disassembler::SubstituteRegisterField(Instruction* instr,
1326 const char* format) {
1327 unsigned reg_num = 0;
1328 unsigned field_len = 2;
1329 switch (format[1]) {
1330 case 'd': reg_num = instr->Rd(); break;
1331 case 'n': reg_num = instr->Rn(); break;
1332 case 'm': reg_num = instr->Rm(); break;
1333 case 'a': reg_num = instr->Ra(); break;
1334 case 't': {
1335 if (format[2] == '2') {
1336 reg_num = instr->Rt2();
1337 field_len = 3;
1338 } else {
1339 reg_num = instr->Rt();
1340 }
1341 break;
1342 }
1343 default: UNREACHABLE();
1344 }
1345
1346 // Increase field length for registers tagged as stack.
1347 if (format[2] == 's') {
1348 field_len = 3;
1349 }
1350
1351 char reg_type;
1352 if (format[0] == 'R') {
1353 // Register type is R: use sf bit to choose X and W.
1354 reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1355 } else if (format[0] == 'F') {
1356 // Floating-point register: use type field to choose S or D.
1357 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1358 } else {
1359 // Register type is specified. Make it lower case.
1360 reg_type = format[0] + 0x20;
1361 }
1362
1363 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1364 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1365
1366 // Filter special registers
1367 if ((reg_type == 'x') && (reg_num == 27)) {
1368 AppendToOutput("cp");
1369 } else if ((reg_type == 'x') && (reg_num == 28)) {
1370 AppendToOutput("jssp");
1371 } else if ((reg_type == 'x') && (reg_num == 29)) {
1372 AppendToOutput("fp");
1373 } else if ((reg_type == 'x') && (reg_num == 30)) {
1374 AppendToOutput("lr");
1375 } else {
1376 AppendToOutput("%c%d", reg_type, reg_num);
1377 }
1378 } else if (format[2] == 's') {
1379 // Disassemble w31/x31 as stack pointer wcsp/csp.
1380 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
1381 } else {
1382 // Disassemble w31/x31 as zero register wzr/xzr.
1383 AppendToOutput("%czr", reg_type);
1384 }
1385
1386 return field_len;
1387 }
1388
1389
1390 int Disassembler::SubstituteImmediateField(Instruction* instr,
1391 const char* format) {
1392 ASSERT(format[0] == 'I');
1393
1394 switch (format[1]) {
1395 case 'M': { // IMoveImm or IMoveLSL.
1396 if (format[5] == 'I') {
1397 uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1398 AppendToOutput("#0x%" PRIx64, imm);
1399 } else {
1400 ASSERT(format[5] == 'L');
1401 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1402 if (instr->ShiftMoveWide() > 0) {
1403 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1404 }
1405 }
1406 return 8;
1407 }
1408 case 'L': {
1409 switch (format[2]) {
1410 case 'L': { // ILLiteral - Immediate Load Literal.
1411 AppendToOutput("pc%+" PRId64,
1412 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1413 return 9;
1414 }
1415 case 'S': { // ILS - Immediate Load/Store.
1416 if (instr->ImmLS() != 0) {
1417 AppendToOutput(", #%" PRId64, instr->ImmLS());
1418 }
1419 return 3;
1420 }
1421 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1422 if (instr->ImmLSPair() != 0) {
1423 // format[3] is the scale value. Convert to a number.
1424 int scale = format[3] - 0x30;
1425 AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1426 }
1427 return 4;
1428 }
1429 case 'U': { // ILU - Immediate Load/Store Unsigned.
1430 if (instr->ImmLSUnsigned() != 0) {
1431 AppendToOutput(", #%" PRIu64,
1432 instr->ImmLSUnsigned() << instr->SizeLS());
1433 }
1434 return 3;
1435 }
1436 }
1437 }
1438 case 'C': { // ICondB - Immediate Conditional Branch.
1439 int64_t offset = instr->ImmCondBranch() << 2;
1440 char sign = (offset >= 0) ? '+' : '-';
1441 AppendToOutput("#%c0x%" PRIx64, sign, offset);
1442 return 6;
1443 }
1444 case 'A': { // IAddSub.
1445 ASSERT(instr->ShiftAddSub() <= 1);
1446 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1447 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1448 return 7;
1449 }
1450 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1451 if (format[3] == 'F') { // IFPFBits.
1452 AppendToOutput("#%d", 64 - instr->FPScale());
1453 return 8;
1454 } else {
1455 AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1456 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1457 return 9;
1458 }
1459 }
1460 case 'T': { // ITri - Immediate Triangular Encoded.
1461 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1462 return 4;
1463 }
1464 case 'N': { // INzcv.
1465 int nzcv = (instr->Nzcv() << Flags_offset);
1466 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1467 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1468 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1469 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1470 return 5;
1471 }
1472 case 'P': { // IP - Conditional compare.
1473 AppendToOutput("#%d", instr->ImmCondCmp());
1474 return 2;
1475 }
1476 case 'B': { // Bitfields.
1477 return SubstituteBitfieldImmediateField(instr, format);
1478 }
1479 case 'E': { // IExtract.
1480 AppendToOutput("#%d", instr->ImmS());
1481 return 8;
1482 }
1483 case 'S': { // IS - Test and branch bit.
1484 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1485 instr->ImmTestBranchBit40());
1486 return 2;
1487 }
1488 case 'D': { // IDebug - HLT and BRK instructions.
1489 AppendToOutput("#0x%x", instr->ImmException());
1490 return 6;
1491 }
1492 default: {
1493 UNIMPLEMENTED();
1494 return 0;
1495 }
1496 }
1497 }
1498
1499
1500 int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
1501 const char* format) {
1502 ASSERT((format[0] == 'I') && (format[1] == 'B'));
1503 unsigned r = instr->ImmR();
1504 unsigned s = instr->ImmS();
1505
1506 switch (format[2]) {
1507 case 'r': { // IBr.
1508 AppendToOutput("#%d", r);
1509 return 3;
1510 }
1511 case 's': { // IBs+1 or IBs-r+1.
1512 if (format[3] == '+') {
1513 AppendToOutput("#%d", s + 1);
1514 return 5;
1515 } else {
1516 ASSERT(format[3] == '-');
1517 AppendToOutput("#%d", s - r + 1);
1518 return 7;
1519 }
1520 }
1521 case 'Z': { // IBZ-r.
1522 ASSERT((format[3] == '-') && (format[4] == 'r'));
1523 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
1524 AppendToOutput("#%d", reg_size - r);
1525 return 5;
1526 }
1527 default: {
1528 UNREACHABLE();
1529 return 0;
1530 }
1531 }
1532 }
1533
1534
1535 int Disassembler::SubstituteLiteralField(Instruction* instr,
1536 const char* format) {
1537 ASSERT(strncmp(format, "LValue", 6) == 0);
1538 USE(format);
1539
1540 switch (instr->Mask(LoadLiteralMask)) {
1541 case LDR_w_lit:
1542 case LDR_x_lit:
1543 case LDR_s_lit:
1544 case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
1545 default: UNREACHABLE();
1546 }
1547
1548 return 6;
1549 }
1550
1551
1552 int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
1553 ASSERT(format[0] == 'H');
1554 ASSERT(instr->ShiftDP() <= 0x3);
1555
1556 switch (format[1]) {
1557 case 'D': { // HDP.
1558 ASSERT(instr->ShiftDP() != ROR);
1559 } // Fall through.
1560 case 'L': { // HLo.
1561 if (instr->ImmDPShift() != 0) {
1562 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1563 AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1564 instr->ImmDPShift());
1565 }
1566 return 3;
1567 }
1568 default:
1569 UNIMPLEMENTED();
1570 return 0;
1571 }
1572 }
1573
1574
1575 int Disassembler::SubstituteConditionField(Instruction* instr,
1576 const char* format) {
1577 ASSERT(format[0] == 'C');
1578 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1579 "mi", "pl", "vs", "vc",
1580 "hi", "ls", "ge", "lt",
1581 "gt", "le", "al", "nv" };
1582 int cond;
1583 switch (format[1]) {
1584 case 'B': cond = instr->ConditionBranch(); break;
1585 case 'I': {
1586 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1587 break;
1588 }
1589 default: cond = instr->Condition();
1590 }
1591 AppendToOutput("%s", condition_code[cond]);
1592 return 4;
1593 }
1594
1595
1596 int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
1597 const char* format) {
1598 USE(format);
1599 ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
1600
1601 int offset = instr->ImmPCRel();
1602
1603 // Only ADR (AddrPCRelByte) is supported.
1604 ASSERT(strcmp(format, "AddrPCRelByte") == 0);
1605
1606 char sign = '+';
1607 if (offset < 0) {
1608 offset = -offset;
1609 sign = '-';
1610 }
1611 // TODO(jbramley): Can we print the target address here?
1612 AppendToOutput("#%c0x%x", sign, offset);
1613 return 13;
1614 }
1615
1616
1617 int Disassembler::SubstituteBranchTargetField(Instruction* instr,
1618 const char* format) {
1619 ASSERT(strncmp(format, "BImm", 4) == 0);
1620
1621 int64_t offset = 0;
1622 switch (format[5]) {
1623 // BImmUncn - unconditional branch immediate.
1624 case 'n': offset = instr->ImmUncondBranch(); break;
1625 // BImmCond - conditional branch immediate.
1626 case 'o': offset = instr->ImmCondBranch(); break;
1627 // BImmCmpa - compare and branch immediate.
1628 case 'm': offset = instr->ImmCmpBranch(); break;
1629 // BImmTest - test and branch immediate.
1630 case 'e': offset = instr->ImmTestBranch(); break;
1631 default: UNIMPLEMENTED();
1632 }
1633 offset <<= kInstructionSizeLog2;
1634 char sign = '+';
1635 if (offset < 0) {
1636 offset = -offset;
1637 sign = '-';
1638 }
1639 // TODO(mcapewel): look up pc + offset in label table.
1640 AppendToOutput("#%c0x%" PRIx64, sign, offset);
1641 return 8;
1642 }
1643
1644
1645 int Disassembler::SubstituteExtendField(Instruction* instr,
1646 const char* format) {
1647 ASSERT(strncmp(format, "Ext", 3) == 0);
1648 ASSERT(instr->ExtendMode() <= 7);
1649 USE(format);
1650
1651 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1652 "sxtb", "sxth", "sxtw", "sxtx" };
1653
1654 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1655 // registers becomes lsl.
1656 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1657 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1658 (instr->ExtendMode() == UXTX))) {
1659 if (instr->ImmExtendShift() > 0) {
1660 AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1661 }
1662 } else {
1663 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1664 if (instr->ImmExtendShift() > 0) {
1665 AppendToOutput(" #%d", instr->ImmExtendShift());
1666 }
1667 }
1668 return 3;
1669 }
1670
1671
1672 int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
1673 const char* format) {
1674 ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1675 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1676 "undefined", "undefined", "sxtw", "sxtx" };
1677 USE(format);
1678
1679 unsigned shift = instr->ImmShiftLS();
1680 Extend ext = static_cast<Extend>(instr->ExtendMode());
1681 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1682
1683 unsigned rm = instr->Rm();
1684 if (rm == kZeroRegCode) {
1685 AppendToOutput("%czr", reg_type);
1686 } else {
1687 AppendToOutput("%c%d", reg_type, rm);
1688 }
1689
1690 // Extend mode UXTX is an alias for shift mode LSL here.
1691 if (!((ext == UXTX) && (shift == 0))) {
1692 AppendToOutput(", %s", extend_mode[ext]);
1693 if (shift != 0) {
1694 AppendToOutput(" #%d", instr->SizeLS());
1695 }
1696 }
1697 return 9;
1698 }
1699
1700
1701 int Disassembler::SubstitutePrefetchField(Instruction* instr,
1702 const char* format) {
1703 ASSERT(format[0] == 'P');
1704 USE(format);
1705
1706 int prefetch_mode = instr->PrefetchMode();
1707
1708 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1709 int level = (prefetch_mode >> 1) + 1;
1710 const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1711
1712 AppendToOutput("p%sl%d%s", ls, level, ks);
1713 return 6;
1714 }
1715
1716 int Disassembler::SubstituteBarrierField(Instruction* instr,
1717 const char* format) {
1718 ASSERT(format[0] == 'M');
1719 USE(format);
1720
1721 static const char* options[4][4] = {
1722 { "sy (0b0000)", "oshld", "oshst", "osh" },
1723 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1724 { "sy (0b1000)", "ishld", "ishst", "ish" },
1725 { "sy (0b1100)", "ld", "st", "sy" }
1726 };
1727 int domain = instr->ImmBarrierDomain();
1728 int type = instr->ImmBarrierType();
1729
1730 AppendToOutput("%s", options[domain][type]);
1731 return 1;
1732 }
1733
1734 void Disassembler::ResetOutput() {
1735 buffer_pos_ = 0;
1736 buffer_[buffer_pos_] = 0;
1737 }
1738
1739
1740 void Disassembler::AppendToOutput(const char* format, ...) {
1741 va_list args;
1742 va_start(args, format);
1743 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1744 va_end(args);
1745 }
1746
1747
1748 void PrintDisassembler::ProcessOutput(Instruction* instr) {
1749 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1750 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
1751 GetOutput());
1752 }
1753
1754 } } // namespace v8::internal
1755
1756
1757 namespace disasm {
1758
1759
1760 const char* NameConverter::NameOfAddress(byte* addr) const {
1761 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1762 return tmp_buffer_.start();
1763 }
1764
1765
1766 const char* NameConverter::NameOfConstant(byte* addr) const {
1767 return NameOfAddress(addr);
1768 }
1769
1770
1771 const char* NameConverter::NameOfCPURegister(int reg) const {
1772 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
1773 if (ureg >= v8::internal::kNumberOfRegisters) {
1774 return "noreg";
1775 }
1776 if (ureg == v8::internal::kZeroRegCode) {
1777 return "xzr";
1778 }
1779 v8::internal::OS::SNPrintF(tmp_buffer_, "x%u", ureg);
1780 return tmp_buffer_.start();
1781 }
1782
1783
1784 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1785 UNREACHABLE(); // A64 does not have the concept of a byte register
1786 return "nobytereg";
1787 }
1788
1789
1790 const char* NameConverter::NameOfXMMRegister(int reg) const {
1791 UNREACHABLE(); // A64 does not have any XMM registers
1792 return "noxmmreg";
1793 }
1794
1795
1796 const char* NameConverter::NameInCode(byte* addr) const {
1797 // The default name converter is called for unknown code, so we will not try
1798 // to access any memory.
1799 return "";
1800 }
1801
1802
1803 //------------------------------------------------------------------------------
1804
1805 class BufferDisassembler : public v8::internal::Disassembler {
1806 public:
1807 explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1808 : out_buffer_(out_buffer) { }
1809
1810 ~BufferDisassembler() { }
1811
1812 virtual void ProcessOutput(v8::internal::Instruction* instr) {
1813 v8::internal::OS::SNPrintF(out_buffer_, "%s", GetOutput());
1814 }
1815
1816 private:
1817 v8::internal::Vector<char> out_buffer_;
1818 };
1819
1820 Disassembler::Disassembler(const NameConverter& converter)
1821 : converter_(converter) {}
1822
1823
1824 Disassembler::~Disassembler() {}
1825
1826
1827 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1828 byte* instr) {
1829 v8::internal::Decoder decoder;
1830 BufferDisassembler disasm(buffer);
1831 decoder.AppendVisitor(&disasm);
1832
1833 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
1834 return v8::internal::kInstructionSize;
1835 }
1836
1837
1838 int Disassembler::ConstantPoolSizeAt(byte* instr) {
1839 return v8::internal::Assembler::ConstantPoolSizeAt(
1840 reinterpret_cast<v8::internal::Instruction*>(instr));
1841 }
1842
1843
1844 void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
1845 v8::internal::Decoder decoder;
1846 v8::internal::PrintDisassembler disasm(file);
1847 decoder.AppendVisitor(&disasm);
1848
1849 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
1850 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
1851 }
1852 }
1853
1854 } // namespace disasm
1855
1856 #endif // V8_TARGET_ARCH_A64
OLDNEW
« no previous file with comments | « src/a64/disasm-a64.h ('k') | src/a64/frames-a64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698