| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 8 #if defined(TARGET_ARCH_ARM64) | 8 #if defined(TARGET_ARCH_ARM64) |
| 9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
| 10 | 10 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 // Returns true if the instruction was successfully decoded, false otherwise. | 25 // Returns true if the instruction was successfully decoded, false otherwise. |
| 26 void InstructionDecode(uword pc); | 26 void InstructionDecode(uword pc); |
| 27 | 27 |
| 28 private: | 28 private: |
| 29 // Bottleneck functions to print into the out_buffer. | 29 // Bottleneck functions to print into the out_buffer. |
| 30 void Print(const char* str); | 30 void Print(const char* str); |
| 31 | 31 |
| 32 // Printing of common values. | 32 // Printing of common values. |
| 33 void PrintRegister(int reg, R31Type r31t); | 33 void PrintRegister(int reg, R31Type r31t); |
| 34 void PrintShiftExtendRm(Instr* instr); | 34 void PrintShiftExtendRm(Instr* instr); |
| 35 void PrintMemOperand(Instr* instr); |
| 35 void PrintS(Instr* instr); | 36 void PrintS(Instr* instr); |
| 36 | 37 |
| 37 // Handle formatting of instructions and their options. | 38 // Handle formatting of instructions and their options. |
| 38 int FormatRegister(Instr* instr, const char* option); | 39 int FormatRegister(Instr* instr, const char* option); |
| 39 int FormatOption(Instr* instr, const char* format); | 40 int FormatOption(Instr* instr, const char* format); |
| 40 void Format(Instr* instr, const char* format); | 41 void Format(Instr* instr, const char* format); |
| 41 void Unknown(Instr* instr); | 42 void Unknown(Instr* instr); |
| 42 | 43 |
| 43 // Decode instructions. | 44 // Decode instructions. |
| 44 #define DECODE_OP(op) \ | 45 #define DECODE_OP(op) \ |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 // Shift amount. | 155 // Shift amount. |
| 155 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 156 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 156 remaining_size_in_buffer(), | 157 remaining_size_in_buffer(), |
| 157 " %d", | 158 " %d", |
| 158 extend_shift_amount); | 159 extend_shift_amount); |
| 159 } | 160 } |
| 160 } | 161 } |
| 161 } | 162 } |
| 162 | 163 |
| 163 | 164 |
| 165 void ARM64Decoder::PrintMemOperand(Instr* instr) { |
| 166 const Register rn = instr->RnField(); |
| 167 if (instr->Bit(24) == 1) { |
| 168 // rn + scaled unsigned 12-bit immediate offset. |
| 169 const uint32_t scale = instr->SzField(); |
| 170 const uint32_t imm12 = instr->Imm12Field(); |
| 171 const uint32_t off = imm12 << scale; |
| 172 Print("["); |
| 173 PrintRegister(rn, R31IsSP); |
| 174 if (off != 0) { |
| 175 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 176 remaining_size_in_buffer(), |
| 177 ", #%d", |
| 178 off); |
| 179 } |
| 180 Print("]"); |
| 181 } else { |
| 182 switch (instr->Bits(10, 2)) { |
| 183 case 1: { |
| 184 const int32_t imm9 = instr->SImm9Field(); |
| 185 // rn + signed 9-bit immediate, post-index, writeback. |
| 186 Print("["); |
| 187 PrintRegister(rn, R31IsSP); |
| 188 Print("]"); |
| 189 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 190 remaining_size_in_buffer(), |
| 191 ", #%d !", |
| 192 imm9); |
| 193 break; |
| 194 } |
| 195 case 3: { |
| 196 const int32_t imm9 = instr->SImm9Field(); |
| 197 // rn + signed 9-bit immediate, pre-index, writeback. |
| 198 Print("["); |
| 199 PrintRegister(rn, R31IsSP); |
| 200 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 201 remaining_size_in_buffer(), |
| 202 ", #%d", |
| 203 imm9); |
| 204 Print("] !"); |
| 205 break; |
| 206 } |
| 207 case 2: { |
| 208 const Register rm = instr->RmField(); |
| 209 const Extend ext = instr->ExtendTypeField(); |
| 210 const int s = instr->Bit(12); |
| 211 Print("["); |
| 212 PrintRegister(rn, R31IsSP); |
| 213 Print(", "); |
| 214 PrintRegister(rm, R31IsZR); |
| 215 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 216 remaining_size_in_buffer(), |
| 217 " %s", |
| 218 extend_names[ext]); |
| 219 if (s == 1) { |
| 220 Print(" scaled"); |
| 221 } |
| 222 Print("]"); |
| 223 break; |
| 224 } |
| 225 default: { |
| 226 Print("???"); |
| 227 } |
| 228 } |
| 229 } |
| 230 } |
| 231 |
| 232 |
| 164 // Handle all register based formatting in these functions to reduce the | 233 // Handle all register based formatting in these functions to reduce the |
| 165 // complexity of FormatOption. | 234 // complexity of FormatOption. |
| 166 int ARM64Decoder::FormatRegister(Instr* instr, const char* format) { | 235 int ARM64Decoder::FormatRegister(Instr* instr, const char* format) { |
| 167 ASSERT(format[0] == 'r'); | 236 ASSERT(format[0] == 'r'); |
| 168 if (format[1] == 'n') { // 'rn: Rn register | 237 if (format[1] == 'n') { // 'rn: Rn register |
| 169 int reg = instr->RnField(); | 238 int reg = instr->RnField(); |
| 170 PrintRegister(reg, instr->RnMode()); | 239 PrintRegister(reg, instr->RnMode()); |
| 171 return 2; | 240 return 2; |
| 172 } else if (format[1] == 'd') { // 'rd: Rd register | 241 } else if (format[1] == 'd') { // 'rd: Rd register |
| 173 int reg = instr->RdField(); | 242 int reg = instr->RdField(); |
| 174 PrintRegister(reg, instr->RdMode()); | 243 PrintRegister(reg, instr->RdMode()); |
| 175 return 2; | 244 return 2; |
| 176 } else if (format[1] == 'm') { // 'rm: Rm register | 245 } else if (format[1] == 'm') { // 'rm: Rm register |
| 177 int reg = instr->RmField(); | 246 int reg = instr->RmField(); |
| 178 PrintRegister(reg, R31IsZR); | 247 PrintRegister(reg, R31IsZR); |
| 179 return 2; | 248 return 2; |
| 249 } else if (format[1] == 't') { // 'rt: Rt register |
| 250 int reg = instr->RtField(); |
| 251 PrintRegister(reg, R31IsZR); |
| 252 return 2; |
| 180 } | 253 } |
| 181 UNREACHABLE(); | 254 UNREACHABLE(); |
| 182 return -1; | 255 return -1; |
| 183 } | 256 } |
| 184 | 257 |
| 185 | 258 |
| 186 // FormatOption takes a formatting string and interprets it based on | 259 // FormatOption takes a formatting string and interprets it based on |
| 187 // the current instructions. The format string points to the first | 260 // the current instructions. The format string points to the first |
| 188 // character of the option string (the option escape has already been | 261 // character of the option string (the option escape has already been |
| 189 // consumed by the caller.) FormatOption returns the number of | 262 // consumed by the caller.) FormatOption returns the number of |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 } else if (format[1] == 'f') { | 296 } else if (format[1] == 'f') { |
| 224 ASSERT(STRING_STARTS_WITH(format, "sf")); | 297 ASSERT(STRING_STARTS_WITH(format, "sf")); |
| 225 if (instr->SFField() == 1) { | 298 if (instr->SFField() == 1) { |
| 226 // TODO(zra): If we don't use the w form much, we can omit printing | 299 // TODO(zra): If we don't use the w form much, we can omit printing |
| 227 // this x. | 300 // this x. |
| 228 Print("x"); | 301 Print("x"); |
| 229 } else { | 302 } else { |
| 230 Print("w"); | 303 Print("w"); |
| 231 } | 304 } |
| 232 return 2; | 305 return 2; |
| 306 } else if (format[1] == 'z') { |
| 307 ASSERT(STRING_STARTS_WITH(format, "sz")); |
| 308 const int sz = instr->SzField(); |
| 309 char const* sz_str; |
| 310 switch (sz) { |
| 311 case 0: sz_str = "b"; break; |
| 312 case 1: sz_str = "h"; break; |
| 313 case 2: sz_str = "w"; break; |
| 314 case 3: sz_str = "x"; break; |
| 315 default: sz_str = "?"; break; |
| 316 } |
| 317 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 318 remaining_size_in_buffer(), |
| 319 "%s", |
| 320 sz_str); |
| 321 return 2; |
| 233 } else if (format[1] == ' ') { | 322 } else if (format[1] == ' ') { |
| 234 if (instr->HasS()) { | 323 if (instr->HasS()) { |
| 235 Print("s"); | 324 Print("s"); |
| 236 } | 325 } |
| 237 return 1; | 326 return 1; |
| 238 } else { | 327 } else { |
| 239 UNREACHABLE(); | 328 UNREACHABLE(); |
| 240 } | 329 } |
| 241 } | 330 } |
| 242 case 'r': { | 331 case 'r': { |
| 243 return FormatRegister(instr, format); | 332 return FormatRegister(instr, format); |
| 244 } | 333 } |
| 245 case 'h': { | 334 case 'h': { |
| 246 ASSERT(STRING_STARTS_WITH(format, "hw")); | 335 ASSERT(STRING_STARTS_WITH(format, "hw")); |
| 247 const int shift = instr->HWField() << 4; | 336 const int shift = instr->HWField() << 4; |
| 248 if (shift != 0) { | 337 if (shift != 0) { |
| 249 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 338 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 250 remaining_size_in_buffer(), | 339 remaining_size_in_buffer(), |
| 251 "lsl %d", | 340 "lsl %d", |
| 252 shift); | 341 shift); |
| 253 } | 342 } |
| 254 return 2; | 343 return 2; |
| 255 } | 344 } |
| 345 case 'm': { |
| 346 ASSERT(STRING_STARTS_WITH(format, "memop")); |
| 347 PrintMemOperand(instr); |
| 348 return 5; |
| 349 } |
| 256 default: { | 350 default: { |
| 257 UNREACHABLE(); | 351 UNREACHABLE(); |
| 258 break; | 352 break; |
| 259 } | 353 } |
| 260 } | 354 } |
| 261 UNREACHABLE(); | 355 UNREACHABLE(); |
| 262 return -1; | 356 return -1; |
| 263 } | 357 } |
| 264 | 358 |
| 265 | 359 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 case 3: | 392 case 3: |
| 299 Format(instr, "movk'sf 'rd, 'imm16 'hw"); | 393 Format(instr, "movk'sf 'rd, 'imm16 'hw"); |
| 300 break; | 394 break; |
| 301 default: | 395 default: |
| 302 Unknown(instr); | 396 Unknown(instr); |
| 303 break; | 397 break; |
| 304 } | 398 } |
| 305 } | 399 } |
| 306 | 400 |
| 307 | 401 |
| 402 void ARM64Decoder::DecodeLoadStoreReg(Instr* instr) { |
| 403 if (instr->Bits(25, 2) != 0) { |
| 404 Unknown(instr); |
| 405 return; |
| 406 } |
| 407 if (instr->Bit(22) == 1) { |
| 408 Format(instr, "ldr'sz 'rt, 'memop"); |
| 409 } else { |
| 410 Format(instr, "str'sz 'rt, 'memop"); |
| 411 } |
| 412 } |
| 413 |
| 414 |
| 308 void ARM64Decoder::DecodeAddSubImm(Instr* instr) { | 415 void ARM64Decoder::DecodeAddSubImm(Instr* instr) { |
| 309 switch (instr->Bit(30)) { | 416 switch (instr->Bit(30)) { |
| 310 case 0: | 417 case 0: |
| 311 Format(instr, "addi'sf's 'rd, 'rn, 'imm12s"); | 418 Format(instr, "addi'sf's 'rd, 'rn, 'imm12s"); |
| 312 break; | 419 break; |
| 313 case 1: | 420 case 1: |
| 314 Format(instr, "subi'sf's 'rd, 'rn, 'imm12s"); | 421 Format(instr, "subi'sf's 'rd, 'rn, 'imm12s"); |
| 315 break; | 422 break; |
| 316 default: | 423 default: |
| 317 Unknown(instr); | 424 Unknown(instr); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 DecodeSystem(instr); | 494 DecodeSystem(instr); |
| 388 } else if (instr->IsUnconditionalBranchRegOp()) { | 495 } else if (instr->IsUnconditionalBranchRegOp()) { |
| 389 DecodeUnconditionalBranchReg(instr); | 496 DecodeUnconditionalBranchReg(instr); |
| 390 } else { | 497 } else { |
| 391 Unknown(instr); | 498 Unknown(instr); |
| 392 } | 499 } |
| 393 } | 500 } |
| 394 | 501 |
| 395 | 502 |
| 396 void ARM64Decoder::DecodeLoadStore(Instr* instr) { | 503 void ARM64Decoder::DecodeLoadStore(Instr* instr) { |
| 397 Unknown(instr); | 504 if (instr->IsLoadStoreRegOp()) { |
| 505 DecodeLoadStoreReg(instr); |
| 506 } else { |
| 507 Unknown(instr); |
| 508 } |
| 398 } | 509 } |
| 399 | 510 |
| 400 | 511 |
| 401 void ARM64Decoder::DecodeAddSubShiftExt(Instr* instr) { | 512 void ARM64Decoder::DecodeAddSubShiftExt(Instr* instr) { |
| 402 switch (instr->Bit(30)) { | 513 switch (instr->Bit(30)) { |
| 403 case 0: | 514 case 0: |
| 404 Format(instr, "add'sf's 'rd, 'rn, 'shift_op"); | 515 Format(instr, "add'sf's 'rd, 'rn, 'shift_op"); |
| 405 break; | 516 break; |
| 406 case 1: | 517 case 1: |
| 407 Format(instr, "sub'sf's 'rd, 'rn, 'shift_op"); | 518 Format(instr, "sub'sf's 'rd, 'rn, 'shift_op"); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 human_buffer, | 604 human_buffer, |
| 494 sizeof(human_buffer), | 605 sizeof(human_buffer), |
| 495 pc); | 606 pc); |
| 496 pc += instruction_length; | 607 pc += instruction_length; |
| 497 } | 608 } |
| 498 } | 609 } |
| 499 | 610 |
| 500 } // namespace dart | 611 } // namespace dart |
| 501 | 612 |
| 502 #endif // defined TARGET_ARCH_ARM | 613 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |