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