~ubuntu-branches/ubuntu/vivid/qemu/vivid

« back to all changes in this revision

Viewing changes to disas/libvixl/a64/disasm-a64.cc

  • Committer: Package Import Robot
  • Author(s): dann frazier
  • Date: 2014-02-11 15:41:53 UTC
  • Revision ID: package-import@ubuntu.com-20140211154153-2d001tf0ium08u81
Tags: 1.7.0+dfsg-3ubuntu2
* Backport changes to enable qemu-user-static support for aarch64
* debian/control: add ppc64el to Architectures
* debian/rules: only install qemu-system-aarch64 on arm64.
  Fixes a FTBFS  when built twice in a row on non-arm64 due to a stale
  debian/qemu-system-aarch64 directory

Show diffs side-by-side

added added

removed removed

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