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

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

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