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