github.com/tencent/goom@v1.0.1/internal/arch/arm64asm/inst.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package arm64asm 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 // Op is an ARM64 opcode. 13 type Op uint16 14 15 // NOTE: The actual Op values are defined in tables.go. 16 // They are chosen to simplify instruction decoding and 17 // are not a dense packing from 0 to N, although the 18 // density is high, probably at least 90%. 19 20 // String to string 21 func (op Op) String() string { 22 if op >= Op(len(opstr)) || opstr[op] == "" { 23 return fmt.Sprintf("Op(%d)", int(op)) 24 } 25 return opstr[op] 26 } 27 28 // Inst is a single instruction. 29 type Inst struct { 30 Op Op // Opcode mnemonic 31 Enc uint32 // Raw encoding bits. 32 Args Args // Instruction arguments, in ARM manual order. 33 } 34 35 // String to string 36 func (i Inst) String() string { 37 var args []string 38 for _, arg := range i.Args { 39 if arg == nil { 40 break 41 } 42 args = append(args, arg.String()) 43 } 44 return i.Op.String() + " " + strings.Join(args, ", ") 45 } 46 47 // Args holds the instruction arguments. 48 // If an instruction has fewer than 5 arguments, 49 // the final elements in the array are nil. 50 type Args [5]Arg 51 52 // Arg is a single instruction argument, one of these types: 53 // Reg, RegSP, ImmShift, RegExtshiftAmount, PCRel, MemImmediate, 54 // MemExtend, Imm, Imm64, Imm_hint, Imm_clrex, Imm_dcps, Cond, 55 // Imm_c, Imm_option, Imm_prfop, Pstatefield, Systemreg, Imm_fp 56 // RegisterWithArrangement, RegisterWithArrangementAndIndex. 57 type Arg interface { 58 isArg() 59 String() string 60 } 61 62 // Reg is a single register. 63 // The zero value denotes W0, not the absence of a register. 64 type Reg uint16 65 66 // nolint 67 const ( 68 W0 Reg = iota 69 W1 70 W2 71 W3 72 W4 73 W5 74 W6 75 W7 76 W8 77 W9 78 W10 79 W11 80 W12 81 W13 82 W14 83 W15 84 W16 85 W17 86 W18 87 W19 88 W20 89 W21 90 W22 91 W23 92 W24 93 W25 94 W26 95 W27 96 W28 97 W29 98 W30 99 WZR 100 101 X0 102 X1 103 X2 104 X3 105 X4 106 X5 107 X6 108 X7 109 X8 110 X9 111 X10 112 X11 113 X12 114 X13 115 X14 116 X15 117 X16 118 X17 119 X18 120 X19 121 X20 122 X21 123 X22 124 X23 125 X24 126 X25 127 X26 128 X27 129 X28 130 X29 131 X30 132 XZR 133 134 B0 135 B1 136 B2 137 B3 138 B4 139 B5 140 B6 141 B7 142 B8 143 B9 144 B10 145 B11 146 B12 147 B13 148 B14 149 B15 150 B16 151 B17 152 B18 153 B19 154 B20 155 B21 156 B22 157 B23 158 B24 159 B25 160 B26 161 B27 162 B28 163 B29 164 B30 165 B31 166 167 H0 168 H1 169 H2 170 H3 171 H4 172 H5 173 H6 174 H7 175 H8 176 H9 177 H10 178 H11 179 H12 180 H13 181 H14 182 H15 183 H16 184 H17 185 H18 186 H19 187 H20 188 H21 189 H22 190 H23 191 H24 192 H25 193 H26 194 H27 195 H28 196 H29 197 H30 198 H31 199 200 S0 201 S1 202 S2 203 S3 204 S4 205 S5 206 S6 207 S7 208 S8 209 S9 210 S10 211 S11 212 S12 213 S13 214 S14 215 S15 216 S16 217 S17 218 S18 219 S19 220 S20 221 S21 222 S22 223 S23 224 S24 225 S25 226 S26 227 S27 228 S28 229 S29 230 S30 231 S31 232 233 D0 234 D1 235 D2 236 D3 237 D4 238 D5 239 D6 240 D7 241 D8 242 D9 243 D10 244 D11 245 D12 246 D13 247 D14 248 D15 249 D16 250 D17 251 D18 252 D19 253 D20 254 D21 255 D22 256 D23 257 D24 258 D25 259 D26 260 D27 261 D28 262 D29 263 D30 264 D31 265 266 Q0 267 Q1 268 Q2 269 Q3 270 Q4 271 Q5 272 Q6 273 Q7 274 Q8 275 Q9 276 Q10 277 Q11 278 Q12 279 Q13 280 Q14 281 Q15 282 Q16 283 Q17 284 Q18 285 Q19 286 Q20 287 Q21 288 Q22 289 Q23 290 Q24 291 Q25 292 Q26 293 Q27 294 Q28 295 Q29 296 Q30 297 Q31 298 299 V0 300 V1 301 V2 302 V3 303 V4 304 V5 305 V6 306 V7 307 V8 308 V9 309 V10 310 V11 311 V12 312 V13 313 V14 314 V15 315 V16 316 V17 317 V18 318 V19 319 V20 320 V21 321 V22 322 V23 323 V24 324 V25 325 V26 326 V27 327 V28 328 V29 329 V30 330 V31 331 332 WSP = WZR // These are different registers with the same encoding. 333 SP = XZR // These are different registers with the same encoding. 334 ) 335 336 func (Reg) isArg() {} 337 338 // String to string 339 func (r Reg) String() string { 340 switch { 341 case r == WZR: 342 return "WZR" 343 case r == XZR: 344 return "XZR" 345 case W0 <= r && r <= W30: 346 return fmt.Sprintf("W%d", int(r-W0)) 347 case X0 <= r && r <= X30: 348 return fmt.Sprintf("X%d", int(r-X0)) 349 350 case B0 <= r && r <= B31: 351 return fmt.Sprintf("B%d", int(r-B0)) 352 case H0 <= r && r <= H31: 353 return fmt.Sprintf("H%d", int(r-H0)) 354 case S0 <= r && r <= S31: 355 return fmt.Sprintf("S%d", int(r-S0)) 356 case D0 <= r && r <= D31: 357 return fmt.Sprintf("D%d", int(r-D0)) 358 case Q0 <= r && r <= Q31: 359 return fmt.Sprintf("Q%d", int(r-Q0)) 360 361 case V0 <= r && r <= V31: 362 return fmt.Sprintf("V%d", int(r-V0)) 363 default: 364 return fmt.Sprintf("Reg(%d)", int(r)) 365 } 366 } 367 368 // RegSP represent a register and X31/W31 is regarded as SP/WSP. 369 type RegSP Reg 370 371 func (RegSP) isArg() {} 372 373 // String to string 374 func (r RegSP) String() string { 375 switch Reg(r) { 376 case WSP: 377 return "WSP" 378 case SP: 379 return "SP" 380 default: 381 return Reg(r).String() 382 } 383 } 384 385 // ImmShift Imm Shift 386 type ImmShift struct { 387 imm uint16 388 shift uint8 389 } 390 391 func (ImmShift) isArg() {} 392 393 // String to string 394 func (is ImmShift) String() string { 395 if is.shift == 0 { 396 return fmt.Sprintf("#%#x", is.imm) 397 } 398 if is.shift < 128 { 399 return fmt.Sprintf("#%#x, LSL #%d", is.imm, is.shift) 400 } 401 return fmt.Sprintf("#%#x, MSL #%d", is.imm, is.shift-128) 402 } 403 404 // ExtShift ExtShift 405 type ExtShift uint8 406 407 const ( 408 _ ExtShift = iota 409 uxtb 410 uxth 411 uxtw 412 uxtx 413 sxtb 414 sxth 415 sxtw 416 sxtx 417 lsl 418 lsr 419 asr 420 ror 421 ) 422 423 // String to string 424 func (extShift ExtShift) String() string { 425 switch extShift { 426 case uxtb: 427 return "UXTB" 428 429 case uxth: 430 return "UXTH" 431 432 case uxtw: 433 return "UXTW" 434 435 case uxtx: 436 return "UXTX" 437 438 case sxtb: 439 return "SXTB" 440 441 case sxth: 442 return "SXTH" 443 444 case sxtw: 445 return "SXTW" 446 447 case sxtx: 448 return "SXTX" 449 450 case lsl: 451 return "LSL" 452 453 case lsr: 454 return "LSR" 455 456 case asr: 457 return "ASR" 458 459 case ror: 460 return "ROR" 461 } 462 return "" 463 } 464 465 // nolint 466 // RegExtshiftAmount RegExtshiftAmount 467 type RegExtshiftAmount struct { 468 reg Reg 469 extShift ExtShift 470 amount uint8 471 show_zero bool 472 } 473 474 func (RegExtshiftAmount) isArg() {} 475 476 // String to string 477 func (rea RegExtshiftAmount) String() string { 478 buf := rea.reg.String() 479 if rea.extShift != ExtShift(0) { 480 buf += ", " + rea.extShift.String() 481 if rea.amount != 0 { 482 buf += fmt.Sprintf(" #%d", rea.amount) 483 } 484 if rea.show_zero { 485 buf += fmt.Sprintf(" #%d", rea.amount) 486 } 487 } 488 return buf 489 } 490 491 // PCRel describes a memory address (usually a code label) 492 // as a distance relative to the program counter. 493 type PCRel int64 494 495 func (PCRel) isArg() {} 496 497 // String to string 498 func (r PCRel) String() string { 499 return fmt.Sprintf(".%+#x", uint64(r)) 500 } 501 502 // AddrMode is an ARM addressing mode. 503 type AddrMode uint8 504 505 // nolint 506 const ( 507 _ AddrMode = iota 508 AddrPostIndex // [R], X - use address R, set R = R + X 509 AddrPreIndex // [R, X]! - use address R + X, set R = R + X 510 AddrOffset // [R, X] - use address R + X 511 AddrPostReg // [Rn], Rm - - use address Rn, set Rn = Rn + Rm 512 ) 513 514 // MemImmediate is a memory reference made up of a base R and immediate X. 515 // The effective memory address is R or R+X depending on AddrMode. 516 type MemImmediate struct { 517 Base RegSP 518 Mode AddrMode 519 imm int32 520 } 521 522 func (MemImmediate) isArg() {} 523 524 // String to string 525 func (m MemImmediate) String() string { 526 R := m.Base.String() 527 X := fmt.Sprintf("#%d", m.imm) 528 529 switch m.Mode { 530 case AddrOffset: 531 if X == "#0" { 532 return fmt.Sprintf("[%s]", R) 533 } 534 return fmt.Sprintf("[%s,%s]", R, X) 535 case AddrPreIndex: 536 return fmt.Sprintf("[%s,%s]!", R, X) 537 case AddrPostIndex: 538 return fmt.Sprintf("[%s],%s", R, X) 539 case AddrPostReg: 540 post := Reg(X0) + Reg(m.imm) 541 postR := post.String() 542 return fmt.Sprintf("[%s], %s", R, postR) 543 } 544 return "unimplemented!" 545 } 546 547 // MemExtend is a memory reference made up of a base R and index expression X. 548 // The effective memory address is R or R+X depending on Index, Extend and Amount. 549 type MemExtend struct { 550 Base RegSP 551 Index Reg 552 Extend ExtShift 553 // Amount indicates the index shift amount (but also see ShiftMustBeZero field below). 554 Amount uint8 555 // Refer to ARM reference manual, for byte load/store(register), the index 556 // shift amount must be 0, encoded in "S" as 0 if omitted, or as 1 if present. 557 // a.ShiftMustBeZero is set true indicates the index shift amount must be 0. 558 // In GNU syntax, a #0 shift amount is printed if Amount is 1 but ShiftMustBeZero 559 // is true; #0 is not printed if Amount is 0 and ShiftMustBeZero is true. 560 // Both cases represent shift by 0 bit. 561 ShiftMustBeZero bool 562 } 563 564 func (MemExtend) isArg() {} 565 566 // String to string 567 func (m MemExtend) String() string { 568 Rbase := m.Base.String() 569 RIndex := m.Index.String() 570 if m.ShiftMustBeZero { 571 if m.Amount != 0 { 572 return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String()) 573 } 574 if m.Extend != lsl { 575 return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String()) 576 } 577 return fmt.Sprintf("[%s,%s]", Rbase, RIndex) 578 } 579 if m.Amount != 0 { 580 return fmt.Sprintf("[%s,%s,%s #%d]", Rbase, RIndex, m.Extend.String(), m.Amount) 581 } 582 if m.Extend != lsl { 583 return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String()) 584 } 585 return fmt.Sprintf("[%s,%s]", Rbase, RIndex) 586 } 587 588 // Imm is an integer constant. 589 type Imm struct { 590 Imm uint32 591 Decimal bool 592 } 593 594 func (Imm) isArg() {} 595 596 // String to string 597 func (i Imm) String() string { 598 if !i.Decimal { 599 return fmt.Sprintf("#%#x", i.Imm) 600 } 601 return fmt.Sprintf("#%d", i.Imm) 602 } 603 604 // Imm64 imm 64 605 type Imm64 struct { 606 Imm uint64 607 Decimal bool 608 } 609 610 func (Imm64) isArg() {} 611 612 // String to string 613 func (i Imm64) String() string { 614 if !i.Decimal { 615 return fmt.Sprintf("#%#x", i.Imm) 616 } 617 return fmt.Sprintf("#%d", i.Imm) 618 } 619 620 // nolint 621 // Imm_hint is an integer constant for HINT instruction. 622 type Imm_hint uint8 623 624 func (Imm_hint) isArg() {} 625 626 // String to string 627 func (i Imm_hint) String() string { 628 return fmt.Sprintf("#%#x", uint32(i)) 629 } 630 631 // nolint 632 // Imm_clrex is an integer constant for CLREX instruction. 633 type Imm_clrex uint8 634 635 func (Imm_clrex) isArg() {} 636 637 // String to string 638 func (i Imm_clrex) String() string { 639 if i == 15 { 640 return "" 641 } 642 return fmt.Sprintf("#%#x", uint32(i)) 643 } 644 645 // nolint 646 // Imm_dcps is an integer constant for DCPS[123] instruction. 647 type Imm_dcps uint16 648 649 func (Imm_dcps) isArg() {} 650 651 // String to string 652 func (i Imm_dcps) String() string { 653 if i == 0 { 654 return "" 655 } 656 return fmt.Sprintf("#%#x", uint32(i)) 657 } 658 659 // Cond Standard conditions. 660 type Cond struct { 661 Value uint8 662 Invert bool 663 } 664 665 func (Cond) isArg() {} 666 667 // String to string 668 func (c Cond) String() string { 669 cond31 := c.Value >> 1 670 invert := bool((c.Value & 1) == 1) 671 invert = (invert != c.Invert) 672 switch cond31 { 673 case 0: 674 if invert { 675 return "NE" 676 } 677 return "EQ" 678 case 1: 679 if invert { 680 return "CC" 681 } 682 return "CS" 683 case 2: 684 if invert { 685 return "PL" 686 } 687 return "MI" 688 case 3: 689 if invert { 690 return "VC" 691 } 692 return "VS" 693 case 4: 694 if invert { 695 return "LS" 696 } 697 return "HI" 698 case 5: 699 if invert { 700 return "LT" 701 } 702 return "GE" 703 case 6: 704 if invert { 705 return "LE" 706 } 707 return "GT" 708 case 7: 709 return "AL" 710 } 711 return "" 712 } 713 714 // nolint 715 // Imm_c is an integer constant for SYS/SYSL/TLBI instruction. 716 type Imm_c uint8 717 718 func (Imm_c) isArg() {} 719 720 // String to string 721 func (i Imm_c) String() string { 722 return fmt.Sprintf("C%d", uint8(i)) 723 } 724 725 // nolint 726 // Imm_option is an integer constant for DMB/DSB/ISB instruction. 727 type Imm_option uint8 728 729 func (Imm_option) isArg() {} 730 731 // String to string 732 func (i Imm_option) String() string { 733 switch uint8(i) { 734 case 15: 735 return "SY" 736 case 14: 737 return "ST" 738 case 13: 739 return "LD" 740 case 11: 741 return "ISH" 742 case 10: 743 return "ISHST" 744 case 9: 745 return "ISHLD" 746 case 7: 747 return "NSH" 748 case 6: 749 return "NSHST" 750 case 5: 751 return "NSHLD" 752 case 3: 753 return "OSH" 754 case 2: 755 return "OSHST" 756 case 1: 757 return "OSHLD" 758 } 759 return fmt.Sprintf("#%#02x", uint8(i)) 760 } 761 762 // nolint 763 // Imm_prfop is an integer constant for PRFM instruction. 764 type Imm_prfop uint8 765 766 func (Imm_prfop) isArg() {} 767 768 // String to string 769 // nolint 770 func (i Imm_prfop) String() string { 771 prf_type := (i >> 3) & (1<<2 - 1) 772 prf_target := (i >> 1) & (1<<2 - 1) 773 prf_policy := i & 1 774 var result string 775 776 switch prf_type { 777 case 0: 778 result = "PLD" 779 case 1: 780 result = "PLI" 781 case 2: 782 result = "PST" 783 case 3: 784 return fmt.Sprintf("#%#02x", uint8(i)) 785 } 786 switch prf_target { 787 case 0: 788 result += "L1" 789 case 1: 790 result += "L2" 791 case 2: 792 result += "L3" 793 case 3: 794 return fmt.Sprintf("#%#02x", uint8(i)) 795 } 796 if prf_policy == 0 { 797 result += "KEEP" 798 } else { 799 result += "STRM" 800 } 801 return result 802 } 803 804 // Pstatefield pstate field 805 type Pstatefield uint8 806 807 // nolint 808 const ( 809 SPSel Pstatefield = iota 810 DAIFSet 811 DAIFClr 812 ) 813 814 func (Pstatefield) isArg() {} 815 816 // String to string 817 func (p Pstatefield) String() string { 818 switch p { 819 case SPSel: 820 return "SPSel" 821 case DAIFSet: 822 return "DAIFSet" 823 case DAIFClr: 824 return "DAIFClr" 825 default: 826 return "unimplemented" 827 } 828 } 829 830 // Systemreg System reg 831 type Systemreg struct { 832 op0 uint8 833 op1 uint8 834 cn uint8 835 cm uint8 836 op2 uint8 837 } 838 839 func (Systemreg) isArg() {} 840 841 // String to string 842 func (s Systemreg) String() string { 843 return fmt.Sprintf("S%d_%d_C%d_C%d_%d", 844 s.op0, s.op1, s.cn, s.cm, s.op2) 845 } 846 847 // nolint 848 // Imm_fp is a signed floating-point constant. 849 type Imm_fp struct { 850 s uint8 851 exp int8 852 pre uint8 853 } 854 855 func (Imm_fp) isArg() {} 856 857 // String to string 858 func (i Imm_fp) String() string { 859 var s, pre, numerator, denominator int16 860 var result float64 861 if i.s == 0 { 862 s = 1 863 } else { 864 s = -1 865 } 866 pre = s * int16(16+i.pre) 867 if i.exp > 0 { 868 numerator = (pre << uint8(i.exp)) 869 denominator = 16 870 } else { 871 numerator = pre 872 denominator = (16 << uint8(-1*i.exp)) 873 } 874 result = float64(numerator) / float64(denominator) 875 return fmt.Sprintf("#%.18e", result) 876 } 877 878 // Arrangement arrangement 879 type Arrangement uint8 880 881 // nolint 882 const ( 883 _ Arrangement = iota 884 ArrangementB 885 Arrangement8B 886 Arrangement16B 887 ArrangementH 888 Arrangement4H 889 Arrangement8H 890 ArrangementS 891 Arrangement2S 892 Arrangement4S 893 ArrangementD 894 Arrangement1D 895 Arrangement2D 896 Arrangement1Q 897 ) 898 899 // String to string 900 func (a Arrangement) String() (result string) { 901 switch a { 902 case ArrangementB: 903 result = ".B" 904 case Arrangement8B: 905 result = ".8B" 906 case Arrangement16B: 907 result = ".16B" 908 case ArrangementH: 909 result = ".H" 910 case Arrangement4H: 911 result = ".4H" 912 case Arrangement8H: 913 result = ".8H" 914 case ArrangementS: 915 result = ".S" 916 case Arrangement2S: 917 result = ".2S" 918 case Arrangement4S: 919 result = ".4S" 920 case ArrangementD: 921 result = ".D" 922 case Arrangement1D: 923 result = ".1D" 924 case Arrangement2D: 925 result = ".2D" 926 case Arrangement1Q: 927 result = ".1Q" 928 } 929 return 930 } 931 932 // RegisterWithArrangement Register with arrangement: <Vd>.<T>, { <Vt>.8B, <Vt2>.8B}, 933 type RegisterWithArrangement struct { 934 r Reg 935 a Arrangement 936 cnt uint8 937 } 938 939 func (RegisterWithArrangement) isArg() {} 940 941 // String to string 942 func (r RegisterWithArrangement) String() string { 943 result := r.r.String() 944 result += r.a.String() 945 if r.cnt > 0 { 946 result = "{" + result 947 if r.cnt == 2 { 948 r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31) 949 result += ", " + r1.String() + r.a.String() 950 } else if r.cnt > 2 { 951 if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 { 952 for i := 1; i < int(r.cnt); i++ { 953 cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31) 954 result += ", " + cur.String() + r.a.String() 955 } 956 } else { 957 r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31) 958 result += "-" + r1.String() + r.a.String() 959 } 960 } 961 result += "}" 962 } 963 return result 964 } 965 966 // RegisterWithArrangementAndIndex Register with arrangement and index: <Vm>.<Ts>[<index>], 967 // 968 // { <Vt>.B, <Vt2>.B }[<index>]. 969 type RegisterWithArrangementAndIndex struct { 970 r Reg 971 a Arrangement 972 index uint8 973 cnt uint8 974 } 975 976 func (RegisterWithArrangementAndIndex) isArg() {} 977 978 // String to string 979 func (r RegisterWithArrangementAndIndex) String() string { 980 result := r.r.String() 981 result += r.a.String() 982 if r.cnt > 0 { 983 result = "{" + result 984 if r.cnt == 2 { 985 r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31) 986 result += ", " + r1.String() + r.a.String() 987 } else if r.cnt > 2 { 988 if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 { 989 for i := 1; i < int(r.cnt); i++ { 990 cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31) 991 result += ", " + cur.String() + r.a.String() 992 } 993 } else { 994 r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31) 995 result += "-" + r1.String() + r.a.String() 996 } 997 } 998 result += "}" 999 } 1000 return fmt.Sprintf("%s[%d]", result, r.index) 1001 }