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

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

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