| 1 | // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
| 2 | // for details. All rights reserved. Use of this source code is governed by a | 
| 3 | // BSD-style license that can be found in the LICENSE file. | 
| 4 |  | 
| 5 | #include "vm/globals.h"  // Needed here to get TARGET_ARCH_ARM64. | 
| 6 | #if defined(TARGET_ARCH_ARM64) | 
| 7 |  | 
| 8 | #include "vm/compiler/assembler/disassembler.h" | 
| 9 |  | 
| 10 | #include "platform/assert.h" | 
| 11 | #include "vm/instructions.h" | 
| 12 |  | 
| 13 | namespace dart { | 
| 14 |  | 
| 15 | #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) | 
| 16 |  | 
| 17 | class ARM64Decoder : public ValueObject { | 
| 18 |  public: | 
| 19 |   ARM64Decoder(char* buffer, size_t buffer_size) | 
| 20 |       : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { | 
| 21 |     buffer_[buffer_pos_] = '\0'; | 
| 22 |   } | 
| 23 |  | 
| 24 |   ~ARM64Decoder() {} | 
| 25 |  | 
| 26 |   // Writes one disassembled instruction into 'buffer' (0-terminated). | 
| 27 |   // Returns true if the instruction was successfully decoded, false otherwise. | 
| 28 |   void InstructionDecode(uword pc); | 
| 29 |  | 
| 30 |  private: | 
| 31 |   // Bottleneck functions to print into the out_buffer. | 
| 32 |   void Print(const char* str); | 
| 33 |  | 
| 34 |   // Printing of common values. | 
| 35 |   void PrintRegister(int reg, R31Type r31t); | 
| 36 |   void PrintVRegister(int reg); | 
| 37 |   void PrintShiftExtendRm(Instr* instr); | 
| 38 |   void PrintMemOperand(Instr* instr); | 
| 39 |   void PrintPairMemOperand(Instr* instr); | 
| 40 |   void PrintS(Instr* instr); | 
| 41 |   void PrintCondition(Instr* instr); | 
| 42 |   void PrintInvertedCondition(Instr* instr); | 
| 43 |  | 
| 44 |   // Handle formatting of instructions and their options. | 
| 45 |   int FormatRegister(Instr* instr, const char* option); | 
| 46 |   int FormatVRegister(Instr* instr, const char* option); | 
| 47 |   int FormatOption(Instr* instr, const char* format); | 
| 48 |   void Format(Instr* instr, const char* format); | 
| 49 |   void Unknown(Instr* instr); | 
| 50 |  | 
| 51 | // Decode instructions. | 
| 52 | #define DECODE_OP(op) void Decode##op(Instr* instr); | 
| 53 |   APPLY_OP_LIST(DECODE_OP) | 
| 54 | #undef DECODE_OP | 
| 55 |  | 
| 56 |   // Convenience functions. | 
| 57 |   char* get_buffer() const { return buffer_; } | 
| 58 |   char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 
| 59 |   size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 
| 60 |  | 
| 61 |   char* buffer_;        // Decode instructions into this buffer. | 
| 62 |   size_t buffer_size_;  // The size of the character buffer. | 
| 63 |   size_t buffer_pos_;   // Current character position in buffer. | 
| 64 |  | 
| 65 |   DISALLOW_ALLOCATION(); | 
| 66 |   DISALLOW_COPY_AND_ASSIGN(ARM64Decoder); | 
| 67 | }; | 
| 68 |  | 
| 69 | // Support for assertions in the ARM64Decoder formatting functions. | 
| 70 | #define STRING_STARTS_WITH(string, compare_string)                             \ | 
| 71 |   (strncmp(string, compare_string, strlen(compare_string)) == 0) | 
| 72 |  | 
| 73 | // Append the str to the output buffer. | 
| 74 | void ARM64Decoder::Print(const char* str) { | 
| 75 |   char cur = *str++; | 
| 76 |   while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { | 
| 77 |     buffer_[buffer_pos_++] = cur; | 
| 78 |     cur = *str++; | 
| 79 |   } | 
| 80 |   buffer_[buffer_pos_] = '\0'; | 
| 81 | } | 
| 82 |  | 
| 83 | // These register names are defined in a way to match the native disassembler | 
| 84 | // formatting, except for register aliases ctx (r9), pp (r10) and sp (r19). | 
| 85 | // See for example the command "objdump -d <binary file>". | 
| 86 | static const char* reg_names[kNumberOfCpuRegisters] = { | 
| 87 |     "r0" ,  "r1" ,  "r2" ,  "r3" ,  "r4" ,  "r5" ,  "r6" ,  "r7" ,  "r8" , "r9" ,  "r10" , | 
| 88 |     "r11" , "r12" , "r13" , "r14" , "r15" , "ip0" , "ip1" , "r18" , "sp" , "r20" , "r21" , | 
| 89 |     "nr" ,  "r23" , "r24" , "r25" , "thr" , "pp" ,  "ctx" , "fp" ,  "lr" , "r31" , | 
| 90 | }; | 
| 91 |  | 
| 92 | // Print the register name according to the active name converter. | 
| 93 | void ARM64Decoder::PrintRegister(int reg, R31Type r31t) { | 
| 94 |   ASSERT(0 <= reg); | 
| 95 |   ASSERT(reg < kNumberOfCpuRegisters); | 
| 96 |   if (reg == 31) { | 
| 97 |     const char* rstr = (r31t == R31IsZR) ? "zr"  : "csp" ; | 
| 98 |     Print(rstr); | 
| 99 |   } else { | 
| 100 |     Print(reg_names[reg]); | 
| 101 |   } | 
| 102 | } | 
| 103 |  | 
| 104 | void ARM64Decoder::PrintVRegister(int reg) { | 
| 105 |   ASSERT(0 <= reg); | 
| 106 |   ASSERT(reg < kNumberOfVRegisters); | 
| 107 |   buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 108 |                                 remaining_size_in_buffer(), "v%d" , reg); | 
| 109 | } | 
| 110 |  | 
| 111 | // These shift names are defined in a way to match the native disassembler | 
| 112 | // formatting. See for example the command "objdump -d <binary file>". | 
| 113 | static const char* shift_names[kMaxShift] = {"lsl" , "lsr" , "asr" , "ror" }; | 
| 114 |  | 
| 115 | static const char* extend_names[kMaxExtend] = { | 
| 116 |     "uxtb" , "uxth" , "uxtw" , "uxtx" , "sxtb" , "sxth" , "sxtw" , "sxtx" , | 
| 117 | }; | 
| 118 |  | 
| 119 | // These condition names are defined in a way to match the native disassembler | 
| 120 | // formatting. See for example the command "objdump -d <binary file>". | 
| 121 | static const char* cond_names[kNumberOfConditions] = { | 
| 122 |     "eq" , "ne" , "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , | 
| 123 |     "hi" , "ls" , "ge" , "lt" , "gt" , "le" , "" ,   "invalid" , | 
| 124 | }; | 
| 125 |  | 
| 126 | // Print the condition guarding the instruction. | 
| 127 | void ARM64Decoder::PrintCondition(Instr* instr) { | 
| 128 |   if (instr->IsConditionalSelectOp()) { | 
| 129 |     Print(cond_names[instr->SelectConditionField()]); | 
| 130 |   } else { | 
| 131 |     Print(cond_names[instr->ConditionField()]); | 
| 132 |   } | 
| 133 | } | 
| 134 |  | 
| 135 | // Print the inverse of the condition guarding the instruction. | 
| 136 | void ARM64Decoder::PrintInvertedCondition(Instr* instr) { | 
| 137 |   if (instr->IsConditionalSelectOp()) { | 
| 138 |     Print(cond_names[InvertCondition(instr->SelectConditionField())]); | 
| 139 |   } else { | 
| 140 |     Print(cond_names[InvertCondition(instr->ConditionField())]); | 
| 141 |   } | 
| 142 | } | 
| 143 |  | 
| 144 | // Print the register shift operands for the instruction. Generally used for | 
| 145 | // data processing instructions. | 
| 146 | void ARM64Decoder::PrintShiftExtendRm(Instr* instr) { | 
| 147 |   int rm = instr->RmField(); | 
| 148 |   Shift shift = instr->ShiftTypeField(); | 
| 149 |   int shift_amount = instr->ShiftAmountField(); | 
| 150 |   Extend extend = instr->ExtendTypeField(); | 
| 151 |   int extend_shift_amount = instr->ExtShiftAmountField(); | 
| 152 |  | 
| 153 |   PrintRegister(rm, R31IsZR); | 
| 154 |  | 
| 155 |   if (instr->IsShift() && (shift == LSL) && (shift_amount == 0)) { | 
| 156 |     // Special case for using rm only. | 
| 157 |     return; | 
| 158 |   } | 
| 159 |   if (instr->IsShift()) { | 
| 160 |     // by immediate | 
| 161 |     if ((shift == ROR) && (shift_amount == 0)) { | 
| 162 |       Print(" RRX" ); | 
| 163 |       return; | 
| 164 |     } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { | 
| 165 |       shift_amount = 32; | 
| 166 |     } | 
| 167 |     buffer_pos_ += | 
| 168 |         Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), | 
| 169 |                        " %s #%d" , shift_names[shift], shift_amount); | 
| 170 |   } else { | 
| 171 |     ASSERT(instr->IsExtend()); | 
| 172 |     // by register | 
| 173 |     buffer_pos_ += | 
| 174 |         Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), | 
| 175 |                        " %s" , extend_names[extend]); | 
| 176 |     if (((instr->SFField() == 1) && (extend == UXTX)) || | 
| 177 |         ((instr->SFField() == 0) && (extend == UXTW))) { | 
| 178 |       // Shift amount. | 
| 179 |       buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 180 |                                     remaining_size_in_buffer(), " %d" , | 
| 181 |                                     extend_shift_amount); | 
| 182 |     } | 
| 183 |   } | 
| 184 | } | 
| 185 |  | 
| 186 | void ARM64Decoder::PrintMemOperand(Instr* instr) { | 
| 187 |   const Register rn = instr->RnField(); | 
| 188 |   if (instr->Bit(24) == 1) { | 
| 189 |     // rn + scaled unsigned 12-bit immediate offset. | 
| 190 |     const uint32_t scale = instr->SzField(); | 
| 191 |     const uint32_t imm12 = instr->Imm12Field(); | 
| 192 |     const uint32_t off = imm12 << scale; | 
| 193 |     Print("[" ); | 
| 194 |     PrintRegister(rn, R31IsSP); | 
| 195 |     if (off != 0) { | 
| 196 |       buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 197 |                                     remaining_size_in_buffer(), ", #%d" , off); | 
| 198 |     } | 
| 199 |     Print("]" ); | 
| 200 |   } else { | 
| 201 |     switch (instr->Bits(10, 2)) { | 
| 202 |       case 0: { | 
| 203 |         // rn + signed 9-bit immediate, pre-index, no writeback. | 
| 204 |         const int32_t imm9 = instr->SImm9Field(); | 
| 205 |         Print("[" ); | 
| 206 |         PrintRegister(rn, R31IsSP); | 
| 207 |         buffer_pos_ += | 
| 208 |             Utils::SNPrint(current_position_in_buffer(), | 
| 209 |                            remaining_size_in_buffer(), ", #%d" , imm9); | 
| 210 |         Print("]" ); | 
| 211 |         break; | 
| 212 |       } | 
| 213 |       case 1: { | 
| 214 |         const int32_t imm9 = instr->SImm9Field(); | 
| 215 |         // rn + signed 9-bit immediate, post-index, writeback. | 
| 216 |         Print("[" ); | 
| 217 |         PrintRegister(rn, R31IsSP); | 
| 218 |         Print("]" ); | 
| 219 |         buffer_pos_ += | 
| 220 |             Utils::SNPrint(current_position_in_buffer(), | 
| 221 |                            remaining_size_in_buffer(), ", #%d !" , imm9); | 
| 222 |         break; | 
| 223 |       } | 
| 224 |       case 2: { | 
| 225 |         const Register rm = instr->RmField(); | 
| 226 |         const Extend ext = instr->ExtendTypeField(); | 
| 227 |         const int s = instr->Bit(12); | 
| 228 |         Print("[" ); | 
| 229 |         PrintRegister(rn, R31IsSP); | 
| 230 |         Print(", " ); | 
| 231 |         PrintRegister(rm, R31IsZR); | 
| 232 |         buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 233 |                                       remaining_size_in_buffer(), " %s" , | 
| 234 |                                       extend_names[ext]); | 
| 235 |         if (s == 1) { | 
| 236 |           Print(" scaled" ); | 
| 237 |         } | 
| 238 |         Print("]" ); | 
| 239 |         break; | 
| 240 |       } | 
| 241 |       case 3: { | 
| 242 |         const int32_t imm9 = instr->SImm9Field(); | 
| 243 |         // rn + signed 9-bit immediate, pre-index, writeback. | 
| 244 |         Print("[" ); | 
| 245 |         PrintRegister(rn, R31IsSP); | 
| 246 |         buffer_pos_ += | 
| 247 |             Utils::SNPrint(current_position_in_buffer(), | 
| 248 |                            remaining_size_in_buffer(), ", #%d" , imm9); | 
| 249 |         Print("] !" ); | 
| 250 |         break; | 
| 251 |       } | 
| 252 |       default: { Print("???" ); } | 
| 253 |     } | 
| 254 |   } | 
| 255 | } | 
| 256 |  | 
| 257 | void ARM64Decoder::PrintPairMemOperand(Instr* instr) { | 
| 258 |   const Register rn = instr->RnField(); | 
| 259 |   const uint32_t simm7 = instr->SImm7Field(); | 
| 260 |   const int32_t offset = simm7 << (2 + instr->Bit(31)); | 
| 261 |   Print("[" ); | 
| 262 |   PrintRegister(rn, R31IsSP); | 
| 263 |   switch (instr->Bits(23, 3)) { | 
| 264 |     case 1: | 
| 265 |       // rn + (imm7 << (2 + B31)), post-index, writeback. | 
| 266 |       buffer_pos_ += | 
| 267 |           Utils::SNPrint(current_position_in_buffer(), | 
| 268 |                          remaining_size_in_buffer(), "], #%d !" , offset); | 
| 269 |       break; | 
| 270 |     case 2: | 
| 271 |       // rn + (imm7 << (2 + B31)), pre-index, no writeback. | 
| 272 |       buffer_pos_ += | 
| 273 |           Utils::SNPrint(current_position_in_buffer(), | 
| 274 |                          remaining_size_in_buffer(), ", #%d ]" , offset); | 
| 275 |       break; | 
| 276 |     case 3: | 
| 277 |       // rn + (imm7 << (2 + B31)), pre-index, writeback. | 
| 278 |       buffer_pos_ += | 
| 279 |           Utils::SNPrint(current_position_in_buffer(), | 
| 280 |                          remaining_size_in_buffer(), ", #%d ]!" , offset); | 
| 281 |       break; | 
| 282 |     default: | 
| 283 |       Print(", ???]" ); | 
| 284 |       break; | 
| 285 |   } | 
| 286 | } | 
| 287 |  | 
| 288 | // Handle all register based formatting in these functions to reduce the | 
| 289 | // complexity of FormatOption. | 
| 290 | int ARM64Decoder::FormatRegister(Instr* instr, const char* format) { | 
| 291 |   ASSERT(format[0] == 'r'); | 
| 292 |   if (format[1] == 'n') {  // 'rn: Rn register | 
| 293 |     int reg = instr->RnField(); | 
| 294 |     PrintRegister(reg, instr->RnMode()); | 
| 295 |     return 2; | 
| 296 |   } else if (format[1] == 'd') {  // 'rd: Rd register | 
| 297 |     int reg = instr->RdField(); | 
| 298 |     PrintRegister(reg, instr->RdMode()); | 
| 299 |     return 2; | 
| 300 |   } else if (format[1] == 'm') {  // 'rm: Rm register | 
| 301 |     int reg = instr->RmField(); | 
| 302 |     PrintRegister(reg, R31IsZR); | 
| 303 |     return 2; | 
| 304 |   } else if (format[1] == 't') {  // 'rt: Rt register | 
| 305 |     int reg = instr->RtField(); | 
| 306 |     PrintRegister(reg, R31IsZR); | 
| 307 |     return 2; | 
| 308 |   } else if (format[1] == 'a') {  // 'ra: Ra register | 
| 309 |     int reg = instr->RaField(); | 
| 310 |     PrintRegister(reg, R31IsZR); | 
| 311 |     return 2; | 
| 312 |   } else if (format[1] == 's') {  // 'rs: Rs register | 
| 313 |     int reg = instr->RsField(); | 
| 314 |     PrintRegister(reg, R31IsZR); | 
| 315 |     return 2; | 
| 316 |   } | 
| 317 |   UNREACHABLE(); | 
| 318 |   return -1; | 
| 319 | } | 
| 320 |  | 
| 321 | int ARM64Decoder::FormatVRegister(Instr* instr, const char* format) { | 
| 322 |   ASSERT(format[0] == 'v'); | 
| 323 |   if (format[1] == 'd') { | 
| 324 |     int reg = instr->VdField(); | 
| 325 |     PrintVRegister(reg); | 
| 326 |     return 2; | 
| 327 |   } else if (format[1] == 'n') { | 
| 328 |     int reg = instr->VnField(); | 
| 329 |     PrintVRegister(reg); | 
| 330 |     return 2; | 
| 331 |   } else if (format[1] == 'm') { | 
| 332 |     int reg = instr->VmField(); | 
| 333 |     PrintVRegister(reg); | 
| 334 |     return 2; | 
| 335 |   } else if (format[1] == 't') { | 
| 336 |     int reg = instr->VtField(); | 
| 337 |     PrintVRegister(reg); | 
| 338 |     return 2; | 
| 339 |   } | 
| 340 |   UNREACHABLE(); | 
| 341 |   return -1; | 
| 342 | } | 
| 343 |  | 
| 344 | // FormatOption takes a formatting string and interprets it based on | 
| 345 | // the current instructions. The format string points to the first | 
| 346 | // character of the option string (the option escape has already been | 
| 347 | // consumed by the caller.)  FormatOption returns the number of | 
| 348 | // characters that were consumed from the formatting string. | 
| 349 | int ARM64Decoder::FormatOption(Instr* instr, const char* format) { | 
| 350 |   switch (format[0]) { | 
| 351 |     case 'b': { | 
| 352 |       if (format[3] == 'i') { | 
| 353 |         ASSERT(STRING_STARTS_WITH(format, "bitimm" )); | 
| 354 |         const uint64_t imm = instr->ImmLogical(); | 
| 355 |         buffer_pos_ += | 
| 356 |             Utils::SNPrint(current_position_in_buffer(), | 
| 357 |                            remaining_size_in_buffer(), "0x%"  Px64, imm); | 
| 358 |         return 6; | 
| 359 |       } else { | 
| 360 |         ASSERT(STRING_STARTS_WITH(format, "bitpos" )); | 
| 361 |         int bitpos = instr->Bits(19, 5) | (instr->Bit(31) << 5); | 
| 362 |         buffer_pos_ += | 
| 363 |             Utils::SNPrint(current_position_in_buffer(), | 
| 364 |                            remaining_size_in_buffer(), "#%d" , bitpos); | 
| 365 |         return 6; | 
| 366 |       } | 
| 367 |     } | 
| 368 |     case 'c': { | 
| 369 |       if (format[1] == 's') { | 
| 370 |         ASSERT(STRING_STARTS_WITH(format, "csz" )); | 
| 371 |         const int32_t imm5 = instr->Bits(16, 5); | 
| 372 |         char const* typ = "??" ; | 
| 373 |         if (imm5 & 0x1) { | 
| 374 |           typ = "b" ; | 
| 375 |         } else if (imm5 & 0x2) { | 
| 376 |           typ = "h" ; | 
| 377 |         } else if (imm5 & 0x4) { | 
| 378 |           typ = "s" ; | 
| 379 |         } else if (imm5 & 0x8) { | 
| 380 |           typ = "d" ; | 
| 381 |         } | 
| 382 |         buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 383 |                                       remaining_size_in_buffer(), "%s" , typ); | 
| 384 |         return 3; | 
| 385 |       } else { | 
| 386 |         ASSERT(STRING_STARTS_WITH(format, "cond" )); | 
| 387 |         if (format[4] == 'i') { | 
| 388 |           ASSERT(STRING_STARTS_WITH(format, "condinverted" )); | 
| 389 |           PrintInvertedCondition(instr); | 
| 390 |           return 12; | 
| 391 |         } else { | 
| 392 |           PrintCondition(instr); | 
| 393 |           return 4; | 
| 394 |         } | 
| 395 |       } | 
| 396 |     } | 
| 397 |     case 'd': { | 
| 398 |       int64_t off; | 
| 399 |       if (format[4] == '2') { | 
| 400 |         ASSERT(STRING_STARTS_WITH(format, "dest26" )); | 
| 401 |         off = static_cast<uint64_t>(instr->SImm26Field()) << 2; | 
| 402 |       } else { | 
| 403 |         if (format[5] == '4') { | 
| 404 |           ASSERT(STRING_STARTS_WITH(format, "dest14" )); | 
| 405 |           off = static_cast<uint64_t>(instr->SImm14Field()) << 2; | 
| 406 |         } else { | 
| 407 |           ASSERT(STRING_STARTS_WITH(format, "dest19" )); | 
| 408 |           off = static_cast<uint64_t>(instr->SImm19Field()) << 2; | 
| 409 |         } | 
| 410 |       } | 
| 411 |       if (FLAG_disassemble_relative) { | 
| 412 |         buffer_pos_ += | 
| 413 |             Utils::SNPrint(current_position_in_buffer(), | 
| 414 |                            remaining_size_in_buffer(), "%+"  Pd64 "" , off); | 
| 415 |       } else { | 
| 416 |         uword destination = reinterpret_cast<uword>(instr) + off; | 
| 417 |         buffer_pos_ += | 
| 418 |             Utils::SNPrint(current_position_in_buffer(), | 
| 419 |                            remaining_size_in_buffer(), "%#"  Px "" , destination); | 
| 420 |       } | 
| 421 |       return 6; | 
| 422 |     } | 
| 423 |     case 'f': { | 
| 424 |       ASSERT(STRING_STARTS_WITH(format, "fsz" )); | 
| 425 |       const int sz = instr->SzField(); | 
| 426 |       char const* sz_str; | 
| 427 |       switch (sz) { | 
| 428 |         case 0: | 
| 429 |           if (instr->Bit(23) == 1) { | 
| 430 |             sz_str = "q" ; | 
| 431 |           } else { | 
| 432 |             sz_str = "b" ; | 
| 433 |           } | 
| 434 |           break; | 
| 435 |         case 1: | 
| 436 |           sz_str = "h" ; | 
| 437 |           break; | 
| 438 |         case 2: | 
| 439 |           sz_str = "s" ; | 
| 440 |           break; | 
| 441 |         case 3: | 
| 442 |           sz_str = "d" ; | 
| 443 |           break; | 
| 444 |         default: | 
| 445 |           sz_str = "?" ; | 
| 446 |           break; | 
| 447 |       } | 
| 448 |       buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 449 |                                     remaining_size_in_buffer(), "%s" , sz_str); | 
| 450 |       return 3; | 
| 451 |     } | 
| 452 |     case 'h': { | 
| 453 |       ASSERT(STRING_STARTS_WITH(format, "hw" )); | 
| 454 |       const int shift = instr->HWField() << 4; | 
| 455 |       if (shift != 0) { | 
| 456 |         buffer_pos_ += | 
| 457 |             Utils::SNPrint(current_position_in_buffer(), | 
| 458 |                            remaining_size_in_buffer(), "lsl %d" , shift); | 
| 459 |       } | 
| 460 |       return 2; | 
| 461 |     } | 
| 462 |     case 'i': {  // 'imm12, 'imm16, 'immd | 
| 463 |       if (format[1] == 'd') { | 
| 464 |         // Element index for a SIMD copy instruction. | 
| 465 |         ASSERT(STRING_STARTS_WITH(format, "idx" )); | 
| 466 |         const int32_t imm4 = instr->Bits(11, 4); | 
| 467 |         const int32_t imm5 = instr->Bits(16, 5); | 
| 468 |         int32_t shift = 0; | 
| 469 |         int32_t imm = -1; | 
| 470 |         if (format[3] == '4') { | 
| 471 |           imm = imm4; | 
| 472 |         } else if (format[3] == '5') { | 
| 473 |           imm = imm5; | 
| 474 |           shift = 1; | 
| 475 |         } | 
| 476 |         int32_t idx = -1; | 
| 477 |         if (imm5 & 0x1) { | 
| 478 |           idx = imm >> shift; | 
| 479 |         } else if (imm5 & 0x2) { | 
| 480 |           idx = imm >> (shift + 1); | 
| 481 |         } else if (imm5 & 0x4) { | 
| 482 |           idx = imm >> (shift + 2); | 
| 483 |         } else if (imm5 & 0x8) { | 
| 484 |           idx = imm >> (shift + 3); | 
| 485 |         } | 
| 486 |         buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 487 |                                       remaining_size_in_buffer(), "[%d]" , idx); | 
| 488 |         return 4; | 
| 489 |       } else if (format[3] == '1') { | 
| 490 |         uint64_t imm; | 
| 491 |         int ret = 5; | 
| 492 |         if (format[4] == '2') { | 
| 493 |           ASSERT(STRING_STARTS_WITH(format, "imm12" )); | 
| 494 |           imm = instr->Imm12Field(); | 
| 495 |           if (format[5] == 's') { | 
| 496 |             // shifted immediate. | 
| 497 |             if (instr->Imm12ShiftField() == 1) { | 
| 498 |               imm = imm << 12; | 
| 499 |             } else if ((instr->Imm12ShiftField() & 0x2) != 0) { | 
| 500 |               Print("Unknown Shift" ); | 
| 501 |             } | 
| 502 |             ret = 6; | 
| 503 |           } | 
| 504 |         } else { | 
| 505 |           ASSERT(STRING_STARTS_WITH(format, "imm16" )); | 
| 506 |           imm = instr->Imm16Field(); | 
| 507 |         } | 
| 508 |         buffer_pos_ += | 
| 509 |             Utils::SNPrint(current_position_in_buffer(), | 
| 510 |                            remaining_size_in_buffer(), "0x%"  Px64, imm); | 
| 511 |         return ret; | 
| 512 |       } else { | 
| 513 |         ASSERT(STRING_STARTS_WITH(format, "imm" )); | 
| 514 |         if (format[3] == 'd') { | 
| 515 |           double dimm = bit_cast<double, int64_t>( | 
| 516 |               Instr::VFPExpandImm(instr->Imm8Field())); | 
| 517 |           buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 518 |                                         remaining_size_in_buffer(), "%f" , dimm); | 
| 519 |           return 4; | 
| 520 |         } else if (format[3] == 'r') { | 
| 521 |           int immr = instr->ImmRField(); | 
| 522 |           buffer_pos_ += | 
| 523 |               Utils::SNPrint(current_position_in_buffer(), | 
| 524 |                              remaining_size_in_buffer(), "#%d" , immr); | 
| 525 |           return 4; | 
| 526 |         } else { | 
| 527 |           ASSERT(format[3] == 's'); | 
| 528 |           int imms = instr->ImmSField(); | 
| 529 |           buffer_pos_ += | 
| 530 |               Utils::SNPrint(current_position_in_buffer(), | 
| 531 |                              remaining_size_in_buffer(), "#%d" , imms); | 
| 532 |           return 4; | 
| 533 |         } | 
| 534 |       } | 
| 535 |     } | 
| 536 |     case 'm': { | 
| 537 |       ASSERT(STRING_STARTS_WITH(format, "memop" )); | 
| 538 |       PrintMemOperand(instr); | 
| 539 |       return 5; | 
| 540 |     } | 
| 541 |     case 'p': { | 
| 542 |       if (format[1] == 'c') { | 
| 543 |         if (format[2] == 'a') { | 
| 544 |           ASSERT(STRING_STARTS_WITH(format, "pcadr" )); | 
| 545 |           const uint64_t immhi = instr->SImm19Field(); | 
| 546 |           const uint64_t immlo = instr->Bits(29, 2); | 
| 547 |           const uint64_t off = (immhi << 2) | immlo; | 
| 548 |           const uint64_t pc = reinterpret_cast<int64_t>(instr); | 
| 549 |           const uint64_t dest = pc + off; | 
| 550 |           buffer_pos_ += | 
| 551 |               Utils::SNPrint(current_position_in_buffer(), | 
| 552 |                              remaining_size_in_buffer(), "0x%"  Px64, dest); | 
| 553 |         } else { | 
| 554 |           ASSERT(STRING_STARTS_WITH(format, "pcldr" )); | 
| 555 |           const uint64_t off = instr->SImm19Field() << 2; | 
| 556 |           const uint64_t pc = reinterpret_cast<int64_t>(instr); | 
| 557 |           const uint64_t dest = pc + off; | 
| 558 |           buffer_pos_ += | 
| 559 |               Utils::SNPrint(current_position_in_buffer(), | 
| 560 |                              remaining_size_in_buffer(), "0x%"  Px64, dest); | 
| 561 |         } | 
| 562 |         return 5; | 
| 563 |       } else { | 
| 564 |         ASSERT(STRING_STARTS_WITH(format, "pmemop" )); | 
| 565 |         PrintPairMemOperand(instr); | 
| 566 |         return 6; | 
| 567 |       } | 
| 568 |     } | 
| 569 |     case 'r': { | 
| 570 |       return FormatRegister(instr, format); | 
| 571 |     } | 
| 572 |     case 'v': { | 
| 573 |       if (format[1] == 's') { | 
| 574 |         ASSERT(STRING_STARTS_WITH(format, "vsz" )); | 
| 575 |         char const* sz_str = NULL; | 
| 576 |         if (instr->Bits(14, 2) == 3) { | 
| 577 |           switch (instr->Bit(22)) { | 
| 578 |             case 0: | 
| 579 |               sz_str = "s" ; | 
| 580 |               break; | 
| 581 |             case 1: | 
| 582 |               sz_str = "d" ; | 
| 583 |               break; | 
| 584 |             default: | 
| 585 |               UNREACHABLE(); | 
| 586 |               break; | 
| 587 |           } | 
| 588 |         } else { | 
| 589 |           switch (instr->Bit(22)) { | 
| 590 |             case 0: | 
| 591 |               sz_str = "w" ; | 
| 592 |               break; | 
| 593 |             case 1: | 
| 594 |               sz_str = "x" ; | 
| 595 |               break; | 
| 596 |             default: | 
| 597 |               UNREACHABLE(); | 
| 598 |               break; | 
| 599 |           } | 
| 600 |         } | 
| 601 |         buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 602 |                                       remaining_size_in_buffer(), "%s" , sz_str); | 
| 603 |         return 3; | 
| 604 |       } else { | 
| 605 |         return FormatVRegister(instr, format); | 
| 606 |       } | 
| 607 |     } | 
| 608 |     case 's': {  // 's: S flag. | 
| 609 |       if (format[1] == 'h') { | 
| 610 |         ASSERT(STRING_STARTS_WITH(format, "shift_op" )); | 
| 611 |         PrintShiftExtendRm(instr); | 
| 612 |         return 8; | 
| 613 |       } else if (format[1] == 'f') { | 
| 614 |         ASSERT(STRING_STARTS_WITH(format, "sf" )); | 
| 615 |         if (instr->SFField() == 1) { | 
| 616 |           // 64-bit width is most commonly used, no need to print "x". | 
| 617 |         } else { | 
| 618 |           Print("w" ); | 
| 619 |         } | 
| 620 |         return 2; | 
| 621 |       } else if (format[1] == 'z') { | 
| 622 |         ASSERT(STRING_STARTS_WITH(format, "sz" )); | 
| 623 |         const int sz = instr->SzField(); | 
| 624 |         char const* sz_str; | 
| 625 |         switch (sz) { | 
| 626 |           case 0: | 
| 627 |             sz_str = "b" ; | 
| 628 |             break; | 
| 629 |           case 1: | 
| 630 |             sz_str = "h" ; | 
| 631 |             break; | 
| 632 |           case 2: | 
| 633 |             sz_str = "w" ; | 
| 634 |             break; | 
| 635 |           case 3: | 
| 636 |             sz_str = "x" ; | 
| 637 |             break; | 
| 638 |           default: | 
| 639 |             sz_str = "?" ; | 
| 640 |             break; | 
| 641 |         } | 
| 642 |         buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), | 
| 643 |                                       remaining_size_in_buffer(), "%s" , sz_str); | 
| 644 |         return 2; | 
| 645 |       } else if (format[1] == ' ') { | 
| 646 |         if (instr->HasS()) { | 
| 647 |           Print("s" ); | 
| 648 |         } | 
| 649 |         return 1; | 
| 650 |       } else { | 
| 651 |         UNREACHABLE(); | 
| 652 |       } | 
| 653 |     } | 
| 654 |     default: { | 
| 655 |       UNREACHABLE(); | 
| 656 |       break; | 
| 657 |     } | 
| 658 |   } | 
| 659 |   UNREACHABLE(); | 
| 660 |   return -1; | 
| 661 | } | 
| 662 |  | 
| 663 | // Format takes a formatting string for a whole instruction and prints it into | 
| 664 | // the output buffer. All escaped options are handed to FormatOption to be | 
| 665 | // parsed further. | 
| 666 | void ARM64Decoder::Format(Instr* instr, const char* format) { | 
| 667 |   char cur = *format++; | 
| 668 |   while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { | 
| 669 |     if (cur == '\'') {  // Single quote is used as the formatting escape. | 
| 670 |       format += FormatOption(instr, format); | 
| 671 |     } else { | 
| 672 |       buffer_[buffer_pos_++] = cur; | 
| 673 |     } | 
| 674 |     cur = *format++; | 
| 675 |   } | 
| 676 |   buffer_[buffer_pos_] = '\0'; | 
| 677 | } | 
| 678 |  | 
| 679 | // For currently unimplemented decodings the disassembler calls Unknown(instr) | 
| 680 | // which will just print "unknown" of the instruction bits. | 
| 681 | void ARM64Decoder::Unknown(Instr* instr) { | 
| 682 |   Format(instr, "unknown" ); | 
| 683 | } | 
| 684 |  | 
| 685 | void ARM64Decoder::DecodeMoveWide(Instr* instr) { | 
| 686 |   switch (instr->Bits(29, 2)) { | 
| 687 |     case 0: | 
| 688 |       Format(instr, "movn'sf 'rd, 'imm16 'hw" ); | 
| 689 |       break; | 
| 690 |     case 2: | 
| 691 |       Format(instr, "movz'sf 'rd, 'imm16 'hw" ); | 
| 692 |       break; | 
| 693 |     case 3: | 
| 694 |       Format(instr, "movk'sf 'rd, 'imm16 'hw" ); | 
| 695 |       break; | 
| 696 |     default: | 
| 697 |       Unknown(instr); | 
| 698 |       break; | 
| 699 |   } | 
| 700 | } | 
| 701 |  | 
| 702 | void ARM64Decoder::DecodeLoadStoreReg(Instr* instr) { | 
| 703 |   if (instr->Bit(26) == 1) { | 
| 704 |     // SIMD or FP src/dst. | 
| 705 |     if (instr->Bit(22) == 1) { | 
| 706 |       Format(instr, "fldr'fsz 'vt, 'memop" ); | 
| 707 |     } else { | 
| 708 |       Format(instr, "fstr'fsz 'vt, 'memop" ); | 
| 709 |     } | 
| 710 |   } else { | 
| 711 |     // Integer src/dst. | 
| 712 |     if (instr->Bits(22, 2) == 0) { | 
| 713 |       Format(instr, "str'sz 'rt, 'memop" ); | 
| 714 |     } else if (instr->Bits(23, 1) == 1) { | 
| 715 |       Format(instr, "ldrs'sz 'rt, 'memop" ); | 
| 716 |     } else { | 
| 717 |       Format(instr, "ldr'sz 'rt, 'memop" ); | 
| 718 |     } | 
| 719 |   } | 
| 720 | } | 
| 721 |  | 
| 722 | void ARM64Decoder::DecodeLoadStoreRegPair(Instr* instr) { | 
| 723 |   if (instr->Bit(22) == 1) { | 
| 724 |     // Load. | 
| 725 |     Format(instr, "ldp'sf 'rt, 'ra, 'pmemop" ); | 
| 726 |   } else { | 
| 727 |     // Store. | 
| 728 |     Format(instr, "stp'sf 'rt, 'ra, 'pmemop" ); | 
| 729 |   } | 
| 730 | } | 
| 731 |  | 
| 732 | void ARM64Decoder::DecodeLoadRegLiteral(Instr* instr) { | 
| 733 |   if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || | 
| 734 |       (instr->Bits(24, 3) != 0)) { | 
| 735 |     Unknown(instr); | 
| 736 |   } | 
| 737 |   if (instr->Bit(30)) { | 
| 738 |     Format(instr, "ldrx 'rt, 'pcldr" ); | 
| 739 |   } else { | 
| 740 |     Format(instr, "ldrw 'rt, 'pcldr" ); | 
| 741 |   } | 
| 742 | } | 
| 743 |  | 
| 744 | void ARM64Decoder::DecodeLoadStoreExclusive(Instr* instr) { | 
| 745 |   if (instr->Bit(21) != 0 || instr->Bit(23) != instr->Bit(15)) { | 
| 746 |     Unknown(instr); | 
| 747 |   } | 
| 748 |   const int32_t size = instr->Bits(30, 2); | 
| 749 |   if (size != 3) { | 
| 750 |     Unknown(instr); | 
| 751 |   } | 
| 752 |  | 
| 753 |   const bool is_load = instr->Bit(22) == 1; | 
| 754 |   const bool is_exclusive = instr->Bit(23) == 0; | 
| 755 |   const bool is_ordered = instr->Bit(15) == 1; | 
| 756 |   if (is_load) { | 
| 757 |     const bool is_load_acquire = !is_exclusive && is_ordered; | 
| 758 |     if (is_load_acquire) { | 
| 759 |       Format(instr, "ldar 'rt, 'rn" ); | 
| 760 |     } else { | 
| 761 |       Format(instr, "ldxr 'rt, 'rn" ); | 
| 762 |     } | 
| 763 |   } else { | 
| 764 |     const bool is_store_release = !is_exclusive && is_ordered; | 
| 765 |     if (is_store_release) { | 
| 766 |       Format(instr, "stlr 'rt, 'rn" ); | 
| 767 |     } else { | 
| 768 |       Format(instr, "stxr 'rs, 'rt, 'rn" ); | 
| 769 |     } | 
| 770 |   } | 
| 771 | } | 
| 772 |  | 
| 773 | void ARM64Decoder::DecodeAddSubImm(Instr* instr) { | 
| 774 |   switch (instr->Bit(30)) { | 
| 775 |     case 0: { | 
| 776 |       if ((instr->RdField() == R31) && (instr->SField() == 1)) { | 
| 777 |         Format(instr, "cmni'sf 'rn, 'imm12s" ); | 
| 778 |       } else { | 
| 779 |         if (((instr->RdField() == R31) || (instr->RnField() == R31)) && | 
| 780 |             (instr->Imm12Field() == 0) && (instr->Bit(29) == 0)) { | 
| 781 |           Format(instr, "mov'sf 'rd, 'rn" ); | 
| 782 |         } else { | 
| 783 |           Format(instr, "addi'sf's 'rd, 'rn, 'imm12s" ); | 
| 784 |         } | 
| 785 |       } | 
| 786 |       break; | 
| 787 |     } | 
| 788 |     case 1: { | 
| 789 |       if ((instr->RdField() == R31) && (instr->SField() == 1)) { | 
| 790 |         Format(instr, "cmpi'sf 'rn, 'imm12s" ); | 
| 791 |       } else { | 
| 792 |         Format(instr, "subi'sf's 'rd, 'rn, 'imm12s" ); | 
| 793 |       } | 
| 794 |       break; | 
| 795 |     } | 
| 796 |     default: | 
| 797 |       Unknown(instr); | 
| 798 |       break; | 
| 799 |   } | 
| 800 | } | 
| 801 |  | 
| 802 | void ARM64Decoder::DecodeBitfield(Instr* instr) { | 
| 803 |   int op = instr->Bits(29, 2); | 
| 804 |   int r_imm = instr->ImmRField(); | 
| 805 |   int s_imm = instr->ImmSField(); | 
| 806 |   switch (op) { | 
| 807 |     case 0: | 
| 808 |       if (r_imm == 0) { | 
| 809 |         if (s_imm == 7) { | 
| 810 |           Format(instr, "sxtb 'rd, 'rn" ); | 
| 811 |           break; | 
| 812 |         } else if (s_imm == 15) { | 
| 813 |           Format(instr, "sxth 'rd, 'rn" ); | 
| 814 |           break; | 
| 815 |         } else if (s_imm == 31) { | 
| 816 |           Format(instr, "sxtw 'rd, 'rn" ); | 
| 817 |           break; | 
| 818 |         } | 
| 819 |       } | 
| 820 |       Format(instr, "sbfm'sf 'rd, 'rn, 'immr, 'imms" ); | 
| 821 |       break; | 
| 822 |     case 1: | 
| 823 |       Format(instr, "bfm'sf 'rd, 'rn, 'immr, 'imms" ); | 
| 824 |       break; | 
| 825 |     case 2: | 
| 826 |       if (r_imm == 0) { | 
| 827 |         if (s_imm == 7) { | 
| 828 |           Format(instr, "uxtb 'rd, 'rn" ); | 
| 829 |           break; | 
| 830 |         } else if (s_imm == 15) { | 
| 831 |           Format(instr, "uxth 'rd, 'rn" ); | 
| 832 |           break; | 
| 833 |         } | 
| 834 |       } | 
| 835 |       Format(instr, "ubfm'sf 'rd, 'rn, 'immr, 'imms" ); | 
| 836 |       break; | 
| 837 |     default: | 
| 838 |       Unknown(instr); | 
| 839 |       break; | 
| 840 |   } | 
| 841 | } | 
| 842 |  | 
| 843 | void ARM64Decoder::DecodeLogicalImm(Instr* instr) { | 
| 844 |   int op = instr->Bits(29, 2); | 
| 845 |   switch (op) { | 
| 846 |     case 0: | 
| 847 |       Format(instr, "andi'sf 'rd, 'rn, 'bitimm" ); | 
| 848 |       break; | 
| 849 |     case 1: { | 
| 850 |       if (instr->RnField() == R31) { | 
| 851 |         Format(instr, "mov'sf 'rd, 'bitimm" ); | 
| 852 |       } else { | 
| 853 |         Format(instr, "orri'sf 'rd, 'rn, 'bitimm" ); | 
| 854 |       } | 
| 855 |       break; | 
| 856 |     } | 
| 857 |     case 2: | 
| 858 |       Format(instr, "eori'sf 'rd, 'rn, 'bitimm" ); | 
| 859 |       break; | 
| 860 |     case 3: | 
| 861 |       Format(instr, "andi'sfs 'rd, 'rn, 'bitimm" ); | 
| 862 |       break; | 
| 863 |     default: | 
| 864 |       Unknown(instr); | 
| 865 |       break; | 
| 866 |   } | 
| 867 | } | 
| 868 |  | 
| 869 | void ARM64Decoder::DecodePCRel(Instr* instr) { | 
| 870 |   const int op = instr->Bit(31); | 
| 871 |   if (op == 0) { | 
| 872 |     Format(instr, "adr 'rd, 'pcadr" ); | 
| 873 |   } else { | 
| 874 |     Unknown(instr); | 
| 875 |   } | 
| 876 | } | 
| 877 |  | 
| 878 | void ARM64Decoder::DecodeDPImmediate(Instr* instr) { | 
| 879 |   if (instr->IsMoveWideOp()) { | 
| 880 |     DecodeMoveWide(instr); | 
| 881 |   } else if (instr->IsAddSubImmOp()) { | 
| 882 |     DecodeAddSubImm(instr); | 
| 883 |   } else if (instr->IsBitfieldOp()) { | 
| 884 |     DecodeBitfield(instr); | 
| 885 |   } else if (instr->IsLogicalImmOp()) { | 
| 886 |     DecodeLogicalImm(instr); | 
| 887 |   } else if (instr->IsPCRelOp()) { | 
| 888 |     DecodePCRel(instr); | 
| 889 |   } else { | 
| 890 |     Unknown(instr); | 
| 891 |   } | 
| 892 | } | 
| 893 |  | 
| 894 | void ARM64Decoder::DecodeExceptionGen(Instr* instr) { | 
| 895 |   if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) && | 
| 896 |       (instr->Bits(21, 3) == 0)) { | 
| 897 |     Format(instr, "svc 'imm16" ); | 
| 898 |   } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | 
| 899 |              (instr->Bits(21, 3) == 1)) { | 
| 900 |     Format(instr, "brk 'imm16" ); | 
| 901 |   } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && | 
| 902 |              (instr->Bits(21, 3) == 2)) { | 
| 903 |     Format(instr, "hlt 'imm16" ); | 
| 904 |   } else { | 
| 905 |     Unknown(instr); | 
| 906 |   } | 
| 907 | } | 
| 908 |  | 
| 909 | void ARM64Decoder::DecodeSystem(Instr* instr) { | 
| 910 |   if (instr->InstructionBits() == CLREX) { | 
| 911 |     Format(instr, "clrex" ); | 
| 912 |     return; | 
| 913 |   } | 
| 914 |  | 
| 915 |   if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) && | 
| 916 |       (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && | 
| 917 |       (instr->Bit(21) == 0)) { | 
| 918 |     if (instr->Bits(8, 4) == 0) { | 
| 919 |       Format(instr, "nop" ); | 
| 920 |     } else { | 
| 921 |       Unknown(instr); | 
| 922 |     } | 
| 923 |   } else { | 
| 924 |     Unknown(instr); | 
| 925 |   } | 
| 926 | } | 
| 927 |  | 
| 928 | void ARM64Decoder::DecodeUnconditionalBranchReg(Instr* instr) { | 
| 929 |   if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 5) == 0) && | 
| 930 |       (instr->Bits(16, 5) == 0x1f)) { | 
| 931 |     switch (instr->Bits(21, 4)) { | 
| 932 |       case 0: | 
| 933 |         Format(instr, "br 'rn" ); | 
| 934 |         break; | 
| 935 |       case 1: | 
| 936 |         Format(instr, "blr 'rn" ); | 
| 937 |         break; | 
| 938 |       case 2: | 
| 939 |         Format(instr, "ret 'rn" ); | 
| 940 |         break; | 
| 941 |       default: | 
| 942 |         Unknown(instr); | 
| 943 |         break; | 
| 944 |     } | 
| 945 |   } | 
| 946 | } | 
| 947 |  | 
| 948 | void ARM64Decoder::DecodeCompareAndBranch(Instr* instr) { | 
| 949 |   const int op = instr->Bit(24); | 
| 950 |   if (op == 0) { | 
| 951 |     Format(instr, "cbz'sf 'rt, 'dest19" ); | 
| 952 |   } else { | 
| 953 |     Format(instr, "cbnz'sf 'rt, 'dest19" ); | 
| 954 |   } | 
| 955 | } | 
| 956 |  | 
| 957 | void ARM64Decoder::DecodeConditionalBranch(Instr* instr) { | 
| 958 |   if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) { | 
| 959 |     Unknown(instr); | 
| 960 |     return; | 
| 961 |   } | 
| 962 |   Format(instr, "b'cond 'dest19" ); | 
| 963 | } | 
| 964 |  | 
| 965 | void ARM64Decoder::DecodeTestAndBranch(Instr* instr) { | 
| 966 |   const int op = instr->Bit(24); | 
| 967 |   if (op == 0) { | 
| 968 |     Format(instr, "tbz'sf 'rt, 'bitpos, 'dest14" ); | 
| 969 |   } else { | 
| 970 |     Format(instr, "tbnz'sf 'rt, 'bitpos, 'dest14" ); | 
| 971 |   } | 
| 972 | } | 
| 973 |  | 
| 974 | void ARM64Decoder::DecodeUnconditionalBranch(Instr* instr) { | 
| 975 |   const int op = instr->Bit(31); | 
| 976 |   if (op == 0) { | 
| 977 |     Format(instr, "b 'dest26" ); | 
| 978 |   } else { | 
| 979 |     Format(instr, "bl 'dest26" ); | 
| 980 |   } | 
| 981 | } | 
| 982 |  | 
| 983 | void ARM64Decoder::DecodeCompareBranch(Instr* instr) { | 
| 984 |   if (instr->IsExceptionGenOp()) { | 
| 985 |     DecodeExceptionGen(instr); | 
| 986 |   } else if (instr->IsSystemOp()) { | 
| 987 |     DecodeSystem(instr); | 
| 988 |   } else if (instr->IsUnconditionalBranchRegOp()) { | 
| 989 |     DecodeUnconditionalBranchReg(instr); | 
| 990 |   } else if (instr->IsCompareAndBranchOp()) { | 
| 991 |     DecodeCompareAndBranch(instr); | 
| 992 |   } else if (instr->IsConditionalBranchOp()) { | 
| 993 |     DecodeConditionalBranch(instr); | 
| 994 |   } else if (instr->IsTestAndBranchOp()) { | 
| 995 |     DecodeTestAndBranch(instr); | 
| 996 |   } else if (instr->IsUnconditionalBranchOp()) { | 
| 997 |     DecodeUnconditionalBranch(instr); | 
| 998 |   } else { | 
| 999 |     Unknown(instr); | 
| 1000 |   } | 
| 1001 | } | 
| 1002 |  | 
| 1003 | void ARM64Decoder::DecodeLoadStore(Instr* instr) { | 
| 1004 |   if (instr->IsLoadStoreRegOp()) { | 
| 1005 |     DecodeLoadStoreReg(instr); | 
| 1006 |   } else if (instr->IsLoadStoreRegPairOp()) { | 
| 1007 |     DecodeLoadStoreRegPair(instr); | 
| 1008 |   } else if (instr->IsLoadRegLiteralOp()) { | 
| 1009 |     DecodeLoadRegLiteral(instr); | 
| 1010 |   } else if (instr->IsLoadStoreExclusiveOp()) { | 
| 1011 |     DecodeLoadStoreExclusive(instr); | 
| 1012 |   } else { | 
| 1013 |     Unknown(instr); | 
| 1014 |   } | 
| 1015 | } | 
| 1016 |  | 
| 1017 | void ARM64Decoder::DecodeAddSubShiftExt(Instr* instr) { | 
| 1018 |   switch (instr->Bit(30)) { | 
| 1019 |     case 0: { | 
| 1020 |       if ((instr->RdField() == R31) && (instr->SFField())) { | 
| 1021 |         Format(instr, "cmn'sf 'rn, 'shift_op" ); | 
| 1022 |       } else { | 
| 1023 |         Format(instr, "add'sf's 'rd, 'rn, 'shift_op" ); | 
| 1024 |       } | 
| 1025 |       break; | 
| 1026 |     } | 
| 1027 |     case 1: { | 
| 1028 |       if ((instr->RdField() == R31) && (instr->SFField())) { | 
| 1029 |         Format(instr, "cmp'sf 'rn, 'shift_op" ); | 
| 1030 |       } else { | 
| 1031 |         Format(instr, "sub'sf's 'rd, 'rn, 'shift_op" ); | 
| 1032 |       } | 
| 1033 |       break; | 
| 1034 |     } | 
| 1035 |     default: | 
| 1036 |       UNREACHABLE(); | 
| 1037 |       break; | 
| 1038 |   } | 
| 1039 | } | 
| 1040 |  | 
| 1041 | void ARM64Decoder::DecodeAddSubWithCarry(Instr* instr) { | 
| 1042 |   switch (instr->Bit(30)) { | 
| 1043 |     case 0: { | 
| 1044 |       Format(instr, "adc'sf's 'rd, 'rn, 'rm" ); | 
| 1045 |       break; | 
| 1046 |     } | 
| 1047 |     case 1: { | 
| 1048 |       Format(instr, "sbc'sf's 'rd, 'rn, 'rm" ); | 
| 1049 |       break; | 
| 1050 |     } | 
| 1051 |     default: | 
| 1052 |       UNREACHABLE(); | 
| 1053 |       break; | 
| 1054 |   } | 
| 1055 | } | 
| 1056 |  | 
| 1057 | void ARM64Decoder::DecodeLogicalShift(Instr* instr) { | 
| 1058 |   const int op = (instr->Bits(29, 2) << 1) | instr->Bit(21); | 
| 1059 |   switch (op) { | 
| 1060 |     case 0: | 
| 1061 |       Format(instr, "and'sf 'rd, 'rn, 'shift_op" ); | 
| 1062 |       break; | 
| 1063 |     case 1: | 
| 1064 |       Format(instr, "bic'sf 'rd, 'rn, 'shift_op" ); | 
| 1065 |       break; | 
| 1066 |     case 2: { | 
| 1067 |       if ((instr->RnField() == R31) && (instr->IsShift()) && | 
| 1068 |           (instr->ShiftTypeField() == LSL)) { | 
| 1069 |         if (instr->ShiftAmountField() == 0) { | 
| 1070 |           Format(instr, "mov'sf 'rd, 'rm" ); | 
| 1071 |         } else { | 
| 1072 |           Format(instr, "lsl'sf 'rd, 'rm, 'imms" ); | 
| 1073 |         } | 
| 1074 |       } else { | 
| 1075 |         Format(instr, "orr'sf 'rd, 'rn, 'shift_op" ); | 
| 1076 |       } | 
| 1077 |       break; | 
| 1078 |     } | 
| 1079 |     case 3: | 
| 1080 |       Format(instr, "orn'sf 'rd, 'rn, 'shift_op" ); | 
| 1081 |       break; | 
| 1082 |     case 4: | 
| 1083 |       Format(instr, "eor'sf 'rd, 'rn, 'shift_op" ); | 
| 1084 |       break; | 
| 1085 |     case 5: | 
| 1086 |       Format(instr, "eon'sf 'rd, 'rn, 'shift_op" ); | 
| 1087 |       break; | 
| 1088 |     case 6: | 
| 1089 |       Format(instr, "and'sfs 'rd, 'rn, 'shift_op" ); | 
| 1090 |       break; | 
| 1091 |     case 7: | 
| 1092 |       Format(instr, "bic'sfs 'rd, 'rn, 'shift_op" ); | 
| 1093 |       break; | 
| 1094 |     default: | 
| 1095 |       UNREACHABLE(); | 
| 1096 |       break; | 
| 1097 |   } | 
| 1098 | } | 
| 1099 |  | 
| 1100 | void ARM64Decoder::DecodeMiscDP1Source(Instr* instr) { | 
| 1101 |   if (instr->Bit(29) != 0) { | 
| 1102 |     Unknown(instr); | 
| 1103 |   } | 
| 1104 |  | 
| 1105 |   const int op = instr->Bits(10, 10); | 
| 1106 |   switch (op) { | 
| 1107 |     case 4: | 
| 1108 |       Format(instr, "clz'sf 'rd, 'rn" ); | 
| 1109 |       break; | 
| 1110 |     default: | 
| 1111 |       Unknown(instr); | 
| 1112 |       break; | 
| 1113 |   } | 
| 1114 | } | 
| 1115 |  | 
| 1116 | void ARM64Decoder::DecodeMiscDP2Source(Instr* instr) { | 
| 1117 |   if (instr->Bit(29) != 0) { | 
| 1118 |     Unknown(instr); | 
| 1119 |   } | 
| 1120 |  | 
| 1121 |   const int op = instr->Bits(10, 5); | 
| 1122 |   switch (op) { | 
| 1123 |     case 2: | 
| 1124 |       Format(instr, "udiv'sf 'rd, 'rn, 'rm" ); | 
| 1125 |       break; | 
| 1126 |     case 3: | 
| 1127 |       Format(instr, "sdiv'sf 'rd, 'rn, 'rm" ); | 
| 1128 |       break; | 
| 1129 |     case 8: | 
| 1130 |       Format(instr, "lsl'sf 'rd, 'rn, 'rm" ); | 
| 1131 |       break; | 
| 1132 |     case 9: | 
| 1133 |       Format(instr, "lsr'sf 'rd, 'rn, 'rm" ); | 
| 1134 |       break; | 
| 1135 |     case 10: | 
| 1136 |       Format(instr, "asr'sf 'rd, 'rn, 'rm" ); | 
| 1137 |       break; | 
| 1138 |     default: | 
| 1139 |       Unknown(instr); | 
| 1140 |       break; | 
| 1141 |   } | 
| 1142 | } | 
| 1143 |  | 
| 1144 | void ARM64Decoder::DecodeMiscDP3Source(Instr* instr) { | 
| 1145 |   bool zero_operand = instr->RaField() == R31; | 
| 1146 |   int32_t mask = B31 | B30 | B29 | B23 | B22 | B21 | B15 | MiscDP3SourceMask; | 
| 1147 |   int32_t bits = instr->InstructionBits() & mask; | 
| 1148 |  | 
| 1149 |   if (bits == MADD || bits == MADDW) { | 
| 1150 |     if (zero_operand) { | 
| 1151 |       Format(instr, "mul'sf 'rd, 'rn, 'rm" ); | 
| 1152 |     } else { | 
| 1153 |       Format(instr, "madd'sf 'rd, 'rn, 'rm, 'ra" ); | 
| 1154 |     } | 
| 1155 |   } else if (bits == MSUB || bits == MSUBW) { | 
| 1156 |     if (zero_operand) { | 
| 1157 |       Format(instr, "mneg'sf 'rd, 'rn, 'rm" ); | 
| 1158 |     } else { | 
| 1159 |       Format(instr, "msub'sf 'rd, 'rn, 'rm, 'ra" ); | 
| 1160 |     } | 
| 1161 |   } else if (bits == SMULH) { | 
| 1162 |     Format(instr, "smulh 'rd, 'rn, 'rm" ); | 
| 1163 |   } else if (bits == UMULH) { | 
| 1164 |     Format(instr, "umulh 'rd, 'rn, 'rm" ); | 
| 1165 |   } else if (bits == UMADDL) { | 
| 1166 |     if (zero_operand) { | 
| 1167 |       Format(instr, "umull 'rd, 'rn, 'rm" ); | 
| 1168 |     } else { | 
| 1169 |       Format(instr, "umaddl 'rd, 'rn, 'rm, 'ra" ); | 
| 1170 |     } | 
| 1171 |   } else if (bits == SMADDL) { | 
| 1172 |     if (zero_operand) { | 
| 1173 |       Format(instr, "smull 'rd, 'rn, 'rm" ); | 
| 1174 |     } else { | 
| 1175 |       Format(instr, "smaddl 'rd, 'rn, 'rm, 'ra" ); | 
| 1176 |     } | 
| 1177 |   } else if (bits == SMSUBL) { | 
| 1178 |     if (zero_operand) { | 
| 1179 |       Format(instr, "smnegl 'rd, 'rn, 'rm" ); | 
| 1180 |     } else { | 
| 1181 |       Format(instr, "smsubl 'rd, 'rn, 'rm, 'ra" ); | 
| 1182 |     } | 
| 1183 |   } else if (bits == UMSUBL) { | 
| 1184 |     if (zero_operand) { | 
| 1185 |       Format(instr, "umnegl 'rd, 'rn, 'rm" ); | 
| 1186 |     } else { | 
| 1187 |       Format(instr, "umsubl 'rd, 'rn, 'rm, 'ra" ); | 
| 1188 |     } | 
| 1189 |   } else { | 
| 1190 |     Unknown(instr); | 
| 1191 |   } | 
| 1192 | } | 
| 1193 |  | 
| 1194 | void ARM64Decoder::DecodeConditionalSelect(Instr* instr) { | 
| 1195 |   int cond = instr->SelectConditionField(); | 
| 1196 |   bool non_select = | 
| 1197 |       (instr->RnField() == instr->RmField()) && ((cond & 0xe) != 0xe); | 
| 1198 |   if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 0)) { | 
| 1199 |     Format(instr, "mov'sf'cond 'rd, 'rn, 'rm" ); | 
| 1200 |   } else if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 1)) { | 
| 1201 |     if (non_select) { | 
| 1202 |       Format(instr, "csinc'sf'cond 'rd, 'rn, 'rm" ); | 
| 1203 |     } else { | 
| 1204 |       Format(instr, "cinc'sf'condinverted 'rd, 'rn" ); | 
| 1205 |     } | 
| 1206 |   } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 0)) { | 
| 1207 |     if (non_select) { | 
| 1208 |       Format(instr, "cinv'sf'condinverted 'rd, 'rn" ); | 
| 1209 |     } else { | 
| 1210 |       Format(instr, "csinv'sf'cond 'rd, 'rn, 'rm" ); | 
| 1211 |     } | 
| 1212 |   } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 1)) { | 
| 1213 |     if (non_select) { | 
| 1214 |       Format(instr, "cneg'sf'condinverted 'rd, 'rn" ); | 
| 1215 |     } else { | 
| 1216 |       Format(instr, "csneg'sf'cond 'rd, 'rn, 'rm" ); | 
| 1217 |     } | 
| 1218 |   } else { | 
| 1219 |     Unknown(instr); | 
| 1220 |   } | 
| 1221 | } | 
| 1222 |  | 
| 1223 | void ARM64Decoder::DecodeDPRegister(Instr* instr) { | 
| 1224 |   if (instr->IsAddSubShiftExtOp()) { | 
| 1225 |     DecodeAddSubShiftExt(instr); | 
| 1226 |   } else if (instr->IsAddSubWithCarryOp()) { | 
| 1227 |     DecodeAddSubWithCarry(instr); | 
| 1228 |   } else if (instr->IsLogicalShiftOp()) { | 
| 1229 |     DecodeLogicalShift(instr); | 
| 1230 |   } else if (instr->IsMiscDP1SourceOp()) { | 
| 1231 |     DecodeMiscDP1Source(instr); | 
| 1232 |   } else if (instr->IsMiscDP2SourceOp()) { | 
| 1233 |     DecodeMiscDP2Source(instr); | 
| 1234 |   } else if (instr->IsMiscDP3SourceOp()) { | 
| 1235 |     DecodeMiscDP3Source(instr); | 
| 1236 |   } else if (instr->IsConditionalSelectOp()) { | 
| 1237 |     DecodeConditionalSelect(instr); | 
| 1238 |   } else { | 
| 1239 |     Unknown(instr); | 
| 1240 |   } | 
| 1241 | } | 
| 1242 |  | 
| 1243 | void ARM64Decoder::DecodeSIMDCopy(Instr* instr) { | 
| 1244 |   const int32_t Q = instr->Bit(30); | 
| 1245 |   const int32_t op = instr->Bit(29); | 
| 1246 |   const int32_t imm4 = instr->Bits(11, 4); | 
| 1247 |  | 
| 1248 |   if ((op == 0) && (imm4 == 7)) { | 
| 1249 |     if (Q == 0) { | 
| 1250 |       Format(instr, "vmovrs 'rd, 'vn'idx5" ); | 
| 1251 |     } else { | 
| 1252 |       Format(instr, "vmovrd 'rd, 'vn'idx5" ); | 
| 1253 |     } | 
| 1254 |   } else if ((Q == 1) && (op == 0) && (imm4 == 0)) { | 
| 1255 |     Format(instr, "vdup'csz 'vd, 'vn'idx5" ); | 
| 1256 |   } else if ((Q == 1) && (op == 0) && (imm4 == 3)) { | 
| 1257 |     Format(instr, "vins'csz 'vd'idx5, 'rn" ); | 
| 1258 |   } else if ((Q == 1) && (op == 0) && (imm4 == 1)) { | 
| 1259 |     Format(instr, "vdup'csz 'vd, 'rn" ); | 
| 1260 |   } else if ((Q == 1) && (op == 1)) { | 
| 1261 |     Format(instr, "vins'csz 'vd'idx5, 'vn'idx4" ); | 
| 1262 |   } else { | 
| 1263 |     Unknown(instr); | 
| 1264 |   } | 
| 1265 | } | 
| 1266 |  | 
| 1267 | void ARM64Decoder::DecodeSIMDThreeSame(Instr* instr) { | 
| 1268 |   const int32_t Q = instr->Bit(30); | 
| 1269 |   const int32_t U = instr->Bit(29); | 
| 1270 |   const int32_t opcode = instr->Bits(11, 5); | 
| 1271 |  | 
| 1272 |   if (Q == 0) { | 
| 1273 |     Unknown(instr); | 
| 1274 |     return; | 
| 1275 |   } | 
| 1276 |  | 
| 1277 |   if ((U == 0) && (opcode == 0x3)) { | 
| 1278 |     if (instr->Bit(23) == 0) { | 
| 1279 |       Format(instr, "vand 'vd, 'vn, 'vm" ); | 
| 1280 |     } else { | 
| 1281 |       Format(instr, "vorr 'vd, 'vn, 'vm" ); | 
| 1282 |     } | 
| 1283 |   } else if ((U == 1) && (opcode == 0x3)) { | 
| 1284 |     Format(instr, "veor 'vd, 'vn, 'vm" ); | 
| 1285 |   } else if ((U == 0) && (opcode == 0x10)) { | 
| 1286 |     Format(instr, "vadd'vsz 'vd, 'vn, 'vm" ); | 
| 1287 |   } else if ((U == 1) && (opcode == 0x10)) { | 
| 1288 |     Format(instr, "vsub'vsz 'vd, 'vn, 'vm" ); | 
| 1289 |   } else if ((U == 0) && (opcode == 0x1a)) { | 
| 1290 |     if (instr->Bit(23) == 0) { | 
| 1291 |       Format(instr, "vadd'vsz 'vd, 'vn, 'vm" ); | 
| 1292 |     } else { | 
| 1293 |       Format(instr, "vsub'vsz 'vd, 'vn, 'vm" ); | 
| 1294 |     } | 
| 1295 |   } else if ((U == 1) && (opcode == 0x1b)) { | 
| 1296 |     Format(instr, "vmul'vsz 'vd, 'vn, 'vm" ); | 
| 1297 |   } else if ((U == 1) && (opcode == 0x1f)) { | 
| 1298 |     Format(instr, "vdiv'vsz 'vd, 'vn, 'vm" ); | 
| 1299 |   } else if ((U == 0) && (opcode == 0x1c)) { | 
| 1300 |     Format(instr, "vceq'vsz 'vd, 'vn, 'vm" ); | 
| 1301 |   } else if ((U == 1) && (opcode == 0x1c)) { | 
| 1302 |     if (instr->Bit(23) == 1) { | 
| 1303 |       Format(instr, "vcgt'vsz 'vd, 'vn, 'vm" ); | 
| 1304 |     } else { | 
| 1305 |       Format(instr, "vcge'vsz 'vd, 'vn, 'vm" ); | 
| 1306 |     } | 
| 1307 |   } else if ((U == 0) && (opcode == 0x1e)) { | 
| 1308 |     if (instr->Bit(23) == 1) { | 
| 1309 |       Format(instr, "vmin'vsz 'vd, 'vn, 'vm" ); | 
| 1310 |     } else { | 
| 1311 |       Format(instr, "vmax'vsz 'vd, 'vn, 'vm" ); | 
| 1312 |     } | 
| 1313 |   } else if ((U == 0) && (opcode == 0x1f)) { | 
| 1314 |     if (instr->Bit(23) == 1) { | 
| 1315 |       Format(instr, "vrsqrt'vsz 'vd, 'vn, 'vm" ); | 
| 1316 |     } else { | 
| 1317 |       Format(instr, "vrecps'vsz 'vd, 'vn, 'vm" ); | 
| 1318 |     } | 
| 1319 |   } else { | 
| 1320 |     Unknown(instr); | 
| 1321 |   } | 
| 1322 | } | 
| 1323 |  | 
| 1324 | void ARM64Decoder::DecodeSIMDTwoReg(Instr* instr) { | 
| 1325 |   const int32_t Q = instr->Bit(30); | 
| 1326 |   const int32_t U = instr->Bit(29); | 
| 1327 |   const int32_t op = instr->Bits(12, 5); | 
| 1328 |   const int32_t sz = instr->Bits(22, 2); | 
| 1329 |  | 
| 1330 |   if (Q == 0) { | 
| 1331 |     Unknown(instr); | 
| 1332 |     return; | 
| 1333 |   } | 
| 1334 |  | 
| 1335 |   if ((U == 1) && (op == 0x5)) { | 
| 1336 |     Format(instr, "vnot 'vd, 'vn" ); | 
| 1337 |   } else if ((U == 0) && (op == 0xf)) { | 
| 1338 |     if (sz == 2) { | 
| 1339 |       Format(instr, "vabss 'vd, 'vn" ); | 
| 1340 |     } else if (sz == 3) { | 
| 1341 |       Format(instr, "vabsd 'vd, 'vn" ); | 
| 1342 |     } else { | 
| 1343 |       Unknown(instr); | 
| 1344 |     } | 
| 1345 |   } else if ((U == 1) && (op == 0xf)) { | 
| 1346 |     if (sz == 2) { | 
| 1347 |       Format(instr, "vnegs 'vd, 'vn" ); | 
| 1348 |     } else if (sz == 3) { | 
| 1349 |       Format(instr, "vnegd 'vd, 'vn" ); | 
| 1350 |     } else { | 
| 1351 |       Unknown(instr); | 
| 1352 |     } | 
| 1353 |   } else if ((U == 1) && (op == 0x1f)) { | 
| 1354 |     if (sz == 2) { | 
| 1355 |       Format(instr, "vsqrts 'vd, 'vn" ); | 
| 1356 |     } else if (sz == 3) { | 
| 1357 |       Format(instr, "vsqrtd 'vd, 'vn" ); | 
| 1358 |     } else { | 
| 1359 |       Unknown(instr); | 
| 1360 |     } | 
| 1361 |   } else if ((U == 0) && (op == 0x1d)) { | 
| 1362 |     if (sz != 2) { | 
| 1363 |       Unknown(instr); | 
| 1364 |       return; | 
| 1365 |     } | 
| 1366 |     Format(instr, "vrecpes 'vd, 'vn" ); | 
| 1367 |   } else if ((U == 1) && (op == 0x1d)) { | 
| 1368 |     if (sz != 2) { | 
| 1369 |       Unknown(instr); | 
| 1370 |       return; | 
| 1371 |     } | 
| 1372 |     Format(instr, "vrsqrtes 'vd, 'vn" ); | 
| 1373 |   } else { | 
| 1374 |     Unknown(instr); | 
| 1375 |   } | 
| 1376 | } | 
| 1377 |  | 
| 1378 | void ARM64Decoder::DecodeDPSimd1(Instr* instr) { | 
| 1379 |   if (instr->IsSIMDCopyOp()) { | 
| 1380 |     DecodeSIMDCopy(instr); | 
| 1381 |   } else if (instr->IsSIMDThreeSameOp()) { | 
| 1382 |     DecodeSIMDThreeSame(instr); | 
| 1383 |   } else if (instr->IsSIMDTwoRegOp()) { | 
| 1384 |     DecodeSIMDTwoReg(instr); | 
| 1385 |   } else { | 
| 1386 |     Unknown(instr); | 
| 1387 |   } | 
| 1388 | } | 
| 1389 |  | 
| 1390 | void ARM64Decoder::DecodeFPImm(Instr* instr) { | 
| 1391 |   if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || (instr->Bit(23) != 0) || | 
| 1392 |       (instr->Bits(5, 5) != 0)) { | 
| 1393 |     Unknown(instr); | 
| 1394 |     return; | 
| 1395 |   } | 
| 1396 |   if (instr->Bit(22) == 1) { | 
| 1397 |     // Double. | 
| 1398 |     Format(instr, "fmovd 'vd, 'immd" ); | 
| 1399 |   } else { | 
| 1400 |     // Single. | 
| 1401 |     Unknown(instr); | 
| 1402 |   } | 
| 1403 | } | 
| 1404 |  | 
| 1405 | void ARM64Decoder::DecodeFPIntCvt(Instr* instr) { | 
| 1406 |   if ((instr->Bit(29) != 0)) { | 
| 1407 |     Unknown(instr); | 
| 1408 |     return; | 
| 1409 |   } | 
| 1410 |  | 
| 1411 |   if ((instr->SFField() == 0) && (instr->Bits(22, 2) == 0)) { | 
| 1412 |     if (instr->Bits(16, 5) == 6) { | 
| 1413 |       Format(instr, "fmovrs'sf 'rd, 'vn" ); | 
| 1414 |     } else if (instr->Bits(16, 5) == 7) { | 
| 1415 |       Format(instr, "fmovsr'sf 'vd, 'rn" ); | 
| 1416 |     } else { | 
| 1417 |       Unknown(instr); | 
| 1418 |     } | 
| 1419 |   } else if (instr->Bits(22, 2) == 1) { | 
| 1420 |     if (instr->Bits(16, 5) == 2) { | 
| 1421 |       Format(instr, "scvtfd'sf 'vd, 'rn" ); | 
| 1422 |     } else if (instr->Bits(16, 5) == 6) { | 
| 1423 |       Format(instr, "fmovrd'sf 'rd, 'vn" ); | 
| 1424 |     } else if (instr->Bits(16, 5) == 7) { | 
| 1425 |       Format(instr, "fmovdr'sf 'vd, 'rn" ); | 
| 1426 |     } else if (instr->Bits(16, 5) == 24) { | 
| 1427 |       Format(instr, "fcvtzds'sf 'rd, 'vn" ); | 
| 1428 |     } else { | 
| 1429 |       Unknown(instr); | 
| 1430 |     } | 
| 1431 |   } else { | 
| 1432 |     Unknown(instr); | 
| 1433 |   } | 
| 1434 | } | 
| 1435 |  | 
| 1436 | void ARM64Decoder::DecodeFPOneSource(Instr* instr) { | 
| 1437 |   const int opc = instr->Bits(15, 6); | 
| 1438 |  | 
| 1439 |   if ((opc != 5) && (instr->Bit(22) != 1)) { | 
| 1440 |     // Source is interpreted as single-precision only if we're doing a | 
| 1441 |     // conversion from single -> double. | 
| 1442 |     Unknown(instr); | 
| 1443 |     return; | 
| 1444 |   } | 
| 1445 |  | 
| 1446 |   switch (opc) { | 
| 1447 |     case 0: | 
| 1448 |       Format(instr, "fmovdd 'vd, 'vn" ); | 
| 1449 |       break; | 
| 1450 |     case 1: | 
| 1451 |       Format(instr, "fabsd 'vd, 'vn" ); | 
| 1452 |       break; | 
| 1453 |     case 2: | 
| 1454 |       Format(instr, "fnegd 'vd, 'vn" ); | 
| 1455 |       break; | 
| 1456 |     case 3: | 
| 1457 |       Format(instr, "fsqrtd 'vd, 'vn" ); | 
| 1458 |       break; | 
| 1459 |     case 4: | 
| 1460 |       Format(instr, "fcvtsd 'vd, 'vn" ); | 
| 1461 |       break; | 
| 1462 |     case 5: | 
| 1463 |       Format(instr, "fcvtds 'vd, 'vn" ); | 
| 1464 |       break; | 
| 1465 |     default: | 
| 1466 |       Unknown(instr); | 
| 1467 |       break; | 
| 1468 |   } | 
| 1469 | } | 
| 1470 |  | 
| 1471 | void ARM64Decoder::DecodeFPTwoSource(Instr* instr) { | 
| 1472 |   if (instr->Bits(22, 2) != 1) { | 
| 1473 |     Unknown(instr); | 
| 1474 |     return; | 
| 1475 |   } | 
| 1476 |   const int opc = instr->Bits(12, 4); | 
| 1477 |  | 
| 1478 |   switch (opc) { | 
| 1479 |     case 0: | 
| 1480 |       Format(instr, "fmuld 'vd, 'vn, 'vm" ); | 
| 1481 |       break; | 
| 1482 |     case 1: | 
| 1483 |       Format(instr, "fdivd 'vd, 'vn, 'vm" ); | 
| 1484 |       break; | 
| 1485 |     case 2: | 
| 1486 |       Format(instr, "faddd 'vd, 'vn, 'vm" ); | 
| 1487 |       break; | 
| 1488 |     case 3: | 
| 1489 |       Format(instr, "fsubd 'vd, 'vn, 'vm" ); | 
| 1490 |       break; | 
| 1491 |     default: | 
| 1492 |       Unknown(instr); | 
| 1493 |       break; | 
| 1494 |   } | 
| 1495 | } | 
| 1496 |  | 
| 1497 | void ARM64Decoder::DecodeFPCompare(Instr* instr) { | 
| 1498 |   if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 0)) { | 
| 1499 |     Format(instr, "fcmpd 'vn, 'vm" ); | 
| 1500 |   } else if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 1)) { | 
| 1501 |     if (instr->VmField() == V0) { | 
| 1502 |       Format(instr, "fcmpd 'vn, #0.0" ); | 
| 1503 |     } else { | 
| 1504 |       Unknown(instr); | 
| 1505 |     } | 
| 1506 |   } else { | 
| 1507 |     Unknown(instr); | 
| 1508 |   } | 
| 1509 | } | 
| 1510 |  | 
| 1511 | void ARM64Decoder::DecodeFP(Instr* instr) { | 
| 1512 |   if (instr->IsFPImmOp()) { | 
| 1513 |     DecodeFPImm(instr); | 
| 1514 |   } else if (instr->IsFPIntCvtOp()) { | 
| 1515 |     DecodeFPIntCvt(instr); | 
| 1516 |   } else if (instr->IsFPOneSourceOp()) { | 
| 1517 |     DecodeFPOneSource(instr); | 
| 1518 |   } else if (instr->IsFPTwoSourceOp()) { | 
| 1519 |     DecodeFPTwoSource(instr); | 
| 1520 |   } else if (instr->IsFPCompareOp()) { | 
| 1521 |     DecodeFPCompare(instr); | 
| 1522 |   } else { | 
| 1523 |     Unknown(instr); | 
| 1524 |   } | 
| 1525 | } | 
| 1526 |  | 
| 1527 | void ARM64Decoder::DecodeDPSimd2(Instr* instr) { | 
| 1528 |   if (instr->IsFPOp()) { | 
| 1529 |     DecodeFP(instr); | 
| 1530 |   } else { | 
| 1531 |     Unknown(instr); | 
| 1532 |   } | 
| 1533 | } | 
| 1534 |  | 
| 1535 | void ARM64Decoder::InstructionDecode(uword pc) { | 
| 1536 |   Instr* instr = Instr::At(pc); | 
| 1537 |  | 
| 1538 |   if (instr->IsDPImmediateOp()) { | 
| 1539 |     DecodeDPImmediate(instr); | 
| 1540 |   } else if (instr->IsCompareBranchOp()) { | 
| 1541 |     DecodeCompareBranch(instr); | 
| 1542 |   } else if (instr->IsLoadStoreOp()) { | 
| 1543 |     DecodeLoadStore(instr); | 
| 1544 |   } else if (instr->IsDPRegisterOp()) { | 
| 1545 |     DecodeDPRegister(instr); | 
| 1546 |   } else if (instr->IsDPSimd1Op()) { | 
| 1547 |     DecodeDPSimd1(instr); | 
| 1548 |   } else if (instr->IsDPSimd2Op()) { | 
| 1549 |     DecodeDPSimd2(instr); | 
| 1550 |   } else { | 
| 1551 |     Unknown(instr); | 
| 1552 |   } | 
| 1553 | } | 
| 1554 |  | 
| 1555 | void Disassembler::DecodeInstruction(char* hex_buffer, | 
| 1556 |                                      intptr_t hex_size, | 
| 1557 |                                      char* human_buffer, | 
| 1558 |                                      intptr_t human_size, | 
| 1559 |                                      int* out_instr_size, | 
| 1560 |                                      const Code& code, | 
| 1561 |                                      Object** object, | 
| 1562 |                                      uword pc) { | 
| 1563 |   ARM64Decoder decoder(human_buffer, human_size); | 
| 1564 |   decoder.InstructionDecode(pc); | 
| 1565 |   int32_t instruction_bits = Instr::At(pc)->InstructionBits(); | 
| 1566 |   Utils::SNPrint(hex_buffer, hex_size, "%08x" , instruction_bits); | 
| 1567 |   if (out_instr_size) { | 
| 1568 |     *out_instr_size = Instr::kInstrSize; | 
| 1569 |   } | 
| 1570 |  | 
| 1571 |   *object = NULL; | 
| 1572 |   if (!code.IsNull()) { | 
| 1573 |     *object = &Object::Handle(); | 
| 1574 |     if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { | 
| 1575 |       *object = NULL; | 
| 1576 |     } | 
| 1577 |   } | 
| 1578 | } | 
| 1579 |  | 
| 1580 | #endif  // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) | 
| 1581 |  | 
| 1582 | }  // namespace dart | 
| 1583 |  | 
| 1584 | #endif  // defined(TARGET_ARCH_ARM64) | 
| 1585 |  |