Source file src/cmd/vendor/golang.org/x/arch/arm64/arm64asm/plan9x.go

     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  	"io"
    10  	"sort"
    11  	"strings"
    12  )
    13  
    14  // GoSyntax returns the Go assembler syntax for the instruction.
    15  // The syntax was originally defined by Plan 9.
    16  // The pc is the program counter of the instruction, used for
    17  // expanding PC-relative addresses into absolute ones.
    18  // The symname function queries the symbol table for the program
    19  // being disassembled. Given a target address it returns the name
    20  // and base address of the symbol containing the target, if any;
    21  // otherwise it returns "", 0.
    22  // The reader text should read from the text segment using text addresses
    23  // as offsets; it is used to display pc-relative loads as constant loads.
    24  func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
    25  	if symname == nil {
    26  		symname = func(uint64) (string, uint64) { return "", 0 }
    27  	}
    28  
    29  	var args []string
    30  	for _, a := range inst.Args {
    31  		if a == nil {
    32  			break
    33  		}
    34  		args = append(args, plan9Arg(&inst, pc, symname, a))
    35  	}
    36  
    37  	op := inst.Op.String()
    38  
    39  	switch inst.Op {
    40  	case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW:
    41  		// Check for PC-relative load.
    42  		if offset, ok := inst.Args[1].(PCRel); ok {
    43  			addr := pc + uint64(offset)
    44  			if _, ok := inst.Args[0].(Reg); !ok {
    45  				break
    46  			}
    47  			if s, base := symname(addr); s != "" && addr == base {
    48  				args[1] = fmt.Sprintf("$%s(SB)", s)
    49  			}
    50  		}
    51  	}
    52  
    53  	// Move addressing mode into opcode suffix.
    54  	suffix := ""
    55  	switch inst.Op {
    56  	case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1, ST1:
    57  		switch mem := inst.Args[1].(type) {
    58  		case MemImmediate:
    59  			switch mem.Mode {
    60  			case AddrOffset:
    61  				// no suffix
    62  			case AddrPreIndex:
    63  				suffix = ".W"
    64  			case AddrPostIndex, AddrPostReg:
    65  				suffix = ".P"
    66  			}
    67  		}
    68  
    69  	case STP, LDP:
    70  		switch mem := inst.Args[2].(type) {
    71  		case MemImmediate:
    72  			switch mem.Mode {
    73  			case AddrOffset:
    74  				// no suffix
    75  			case AddrPreIndex:
    76  				suffix = ".W"
    77  			case AddrPostIndex:
    78  				suffix = ".P"
    79  			}
    80  		}
    81  	}
    82  
    83  	switch inst.Op {
    84  	case BL:
    85  		return "CALL " + args[0]
    86  
    87  	case BLR:
    88  		r := inst.Args[0].(Reg)
    89  		regno := uint16(r) & 31
    90  		return fmt.Sprintf("CALL (R%d)", regno)
    91  
    92  	case RET:
    93  		if r, ok := inst.Args[0].(Reg); ok && r == X30 {
    94  			return "RET"
    95  		}
    96  
    97  	case B:
    98  		if cond, ok := inst.Args[0].(Cond); ok {
    99  			return "B" + cond.String() + " " + args[1]
   100  		}
   101  		return "JMP" + " " + args[0]
   102  
   103  	case BR:
   104  		r := inst.Args[0].(Reg)
   105  		regno := uint16(r) & 31
   106  		return fmt.Sprintf("JMP (R%d)", regno)
   107  
   108  	case MOV:
   109  		rno := -1
   110  		switch a := inst.Args[0].(type) {
   111  		case Reg:
   112  			rno = int(a)
   113  		case RegSP:
   114  			rno = int(a)
   115  		case RegisterWithArrangementAndIndex:
   116  			op = "VMOV"
   117  		case RegisterWithArrangement:
   118  			op = "VMOV"
   119  		}
   120  		if rno >= 0 && rno <= int(WZR) {
   121  			op = "MOVW"
   122  		} else if rno >= int(X0) && rno <= int(XZR) {
   123  			op = "MOVD"
   124  		}
   125  		if _, ok := inst.Args[1].(RegisterWithArrangementAndIndex); ok {
   126  			op = "VMOV"
   127  		}
   128  
   129  	case LDR, LDUR:
   130  		var rno uint16
   131  		if r, ok := inst.Args[0].(Reg); ok {
   132  			rno = uint16(r)
   133  		} else {
   134  			rno = uint16(inst.Args[0].(RegSP))
   135  		}
   136  		if rno <= uint16(WZR) {
   137  			op = "MOVWU" + suffix
   138  		} else if rno >= uint16(B0) && rno <= uint16(B31) {
   139  			op = "FMOVB" + suffix
   140  			args[0] = fmt.Sprintf("F%d", rno&31)
   141  		} else if rno >= uint16(H0) && rno <= uint16(H31) {
   142  			op = "FMOVH" + suffix
   143  			args[0] = fmt.Sprintf("F%d", rno&31)
   144  		} else if rno >= uint16(S0) && rno <= uint16(S31) {
   145  			op = "FMOVS" + suffix
   146  			args[0] = fmt.Sprintf("F%d", rno&31)
   147  		} else if rno >= uint16(D0) && rno <= uint16(D31) {
   148  			op = "FMOVD" + suffix
   149  			args[0] = fmt.Sprintf("F%d", rno&31)
   150  		} else if rno >= uint16(Q0) && rno <= uint16(Q31) {
   151  			op = "FMOVQ" + suffix
   152  			args[0] = fmt.Sprintf("F%d", rno&31)
   153  		} else {
   154  			op = "MOVD" + suffix
   155  		}
   156  
   157  	case LDRB:
   158  		op = "MOVBU" + suffix
   159  
   160  	case LDRH:
   161  		op = "MOVHU" + suffix
   162  
   163  	case LDRSW:
   164  		op = "MOVW" + suffix
   165  
   166  	case LDRSB:
   167  		if r, ok := inst.Args[0].(Reg); ok {
   168  			rno := uint16(r)
   169  			if rno <= uint16(WZR) {
   170  				op = "MOVBW" + suffix
   171  			} else {
   172  				op = "MOVB" + suffix
   173  			}
   174  		}
   175  	case LDRSH:
   176  		if r, ok := inst.Args[0].(Reg); ok {
   177  			rno := uint16(r)
   178  			if rno <= uint16(WZR) {
   179  				op = "MOVHW" + suffix
   180  			} else {
   181  				op = "MOVH" + suffix
   182  			}
   183  		}
   184  	case STR, STUR:
   185  		var rno uint16
   186  		if r, ok := inst.Args[0].(Reg); ok {
   187  			rno = uint16(r)
   188  		} else {
   189  			rno = uint16(inst.Args[0].(RegSP))
   190  		}
   191  		if rno <= uint16(WZR) {
   192  			op = "MOVW" + suffix
   193  		} else if rno >= uint16(B0) && rno <= uint16(B31) {
   194  			op = "FMOVB" + suffix
   195  			args[0] = fmt.Sprintf("F%d", rno&31)
   196  		} else if rno >= uint16(H0) && rno <= uint16(H31) {
   197  			op = "FMOVH" + suffix
   198  			args[0] = fmt.Sprintf("F%d", rno&31)
   199  		} else if rno >= uint16(S0) && rno <= uint16(S31) {
   200  			op = "FMOVS" + suffix
   201  			args[0] = fmt.Sprintf("F%d", rno&31)
   202  		} else if rno >= uint16(D0) && rno <= uint16(D31) {
   203  			op = "FMOVD" + suffix
   204  			args[0] = fmt.Sprintf("F%d", rno&31)
   205  		} else if rno >= uint16(Q0) && rno <= uint16(Q31) {
   206  			op = "FMOVQ" + suffix
   207  			args[0] = fmt.Sprintf("F%d", rno&31)
   208  		} else {
   209  			op = "MOVD" + suffix
   210  		}
   211  		args[0], args[1] = args[1], args[0]
   212  
   213  	case STRB, STURB:
   214  		op = "MOVB" + suffix
   215  		args[0], args[1] = args[1], args[0]
   216  
   217  	case STRH, STURH:
   218  		op = "MOVH" + suffix
   219  		args[0], args[1] = args[1], args[0]
   220  
   221  	case TBNZ, TBZ:
   222  		args[0], args[1], args[2] = args[2], args[0], args[1]
   223  
   224  	case MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL:
   225  		if r, ok := inst.Args[0].(Reg); ok {
   226  			rno := uint16(r)
   227  			if rno <= uint16(WZR) {
   228  				op += "W"
   229  			}
   230  		}
   231  		args[2], args[3] = args[3], args[2]
   232  	case STLR:
   233  		if r, ok := inst.Args[0].(Reg); ok {
   234  			rno := uint16(r)
   235  			if rno <= uint16(WZR) {
   236  				op += "W"
   237  			}
   238  		}
   239  		args[0], args[1] = args[1], args[0]
   240  
   241  	case STLRB, STLRH:
   242  		args[0], args[1] = args[1], args[0]
   243  
   244  	case STLXR, STXR:
   245  		if r, ok := inst.Args[1].(Reg); ok {
   246  			rno := uint16(r)
   247  			if rno <= uint16(WZR) {
   248  				op += "W"
   249  			}
   250  		}
   251  		args[1], args[2] = args[2], args[1]
   252  
   253  	case STLXRB, STLXRH, STXRB, STXRH:
   254  		args[1], args[2] = args[2], args[1]
   255  
   256  	case BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX:
   257  		if r, ok := inst.Args[0].(Reg); ok {
   258  			rno := uint16(r)
   259  			if rno <= uint16(WZR) {
   260  				op += "W"
   261  			}
   262  		}
   263  		args[1], args[2], args[3] = args[3], args[1], args[2]
   264  
   265  	case LDAXP, LDXP:
   266  		if r, ok := inst.Args[0].(Reg); ok {
   267  			rno := uint16(r)
   268  			if rno <= uint16(WZR) {
   269  				op += "W"
   270  			}
   271  		}
   272  		args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
   273  		args[1] = args[2]
   274  		return op + " " + args[1] + ", " + args[0]
   275  
   276  	case STP, LDP:
   277  		args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
   278  		args[1] = args[2]
   279  
   280  		rno, ok := inst.Args[0].(Reg)
   281  		if !ok {
   282  			rno = Reg(inst.Args[0].(RegSP))
   283  		}
   284  		if rno <= WZR {
   285  			op = op + "W"
   286  		} else if rno >= S0 && rno <= S31 {
   287  			op = "F" + op + "S"
   288  		} else if rno >= D0 && rno <= D31 {
   289  			op = "F" + op + "D"
   290  		} else if rno >= Q0 && rno <= Q31 {
   291  			op = "F" + op + "Q"
   292  		}
   293  		op = op + suffix
   294  		if inst.Op.String() == "STP" {
   295  			return op + " " + args[0] + ", " + args[1]
   296  		} else {
   297  			return op + " " + args[1] + ", " + args[0]
   298  		}
   299  
   300  	case STLXP, STXP:
   301  		if r, ok := inst.Args[1].(Reg); ok {
   302  			rno := uint16(r)
   303  			if rno <= uint16(WZR) {
   304  				op += "W"
   305  			}
   306  		}
   307  		args[1] = fmt.Sprintf("(%s, %s)", args[1], args[2])
   308  		args[2] = args[3]
   309  		return op + " " + args[1] + ", " + args[2] + ", " + args[0]
   310  
   311  	case FCCMP, FCCMPE:
   312  		args[0], args[1] = args[1], args[0]
   313  		fallthrough
   314  
   315  	case FCMP, FCMPE:
   316  		if _, ok := inst.Args[1].(Imm); ok {
   317  			args[1] = "$(0.0)"
   318  		}
   319  		fallthrough
   320  
   321  	case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL, FMADD, FMSUB, FNMADD, FNMSUB:
   322  		if strings.HasSuffix(op, "MADD") || strings.HasSuffix(op, "MSUB") {
   323  			args[2], args[3] = args[3], args[2]
   324  		}
   325  		if r, ok := inst.Args[0].(Reg); ok {
   326  			rno := uint16(r)
   327  			if rno >= uint16(S0) && rno <= uint16(S31) {
   328  				op = fmt.Sprintf("%sS", op)
   329  			} else if rno >= uint16(D0) && rno <= uint16(D31) {
   330  				op = fmt.Sprintf("%sD", op)
   331  			}
   332  		}
   333  
   334  	case FCVT:
   335  		for i := 1; i >= 0; i-- {
   336  			if r, ok := inst.Args[i].(Reg); ok {
   337  				rno := uint16(r)
   338  				if rno >= uint16(H0) && rno <= uint16(H31) {
   339  					op = fmt.Sprintf("%sH", op)
   340  				} else if rno >= uint16(S0) && rno <= uint16(S31) {
   341  					op = fmt.Sprintf("%sS", op)
   342  				} else if rno >= uint16(D0) && rno <= uint16(D31) {
   343  					op = fmt.Sprintf("%sD", op)
   344  				}
   345  			}
   346  		}
   347  
   348  	case FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI:
   349  		if r, ok := inst.Args[1].(Reg); ok {
   350  			rno := uint16(r)
   351  			if rno >= uint16(S0) && rno <= uint16(S31) {
   352  				op = fmt.Sprintf("%sS", op)
   353  			} else if rno >= uint16(D0) && rno <= uint16(D31) {
   354  				op = fmt.Sprintf("%sD", op)
   355  			}
   356  		}
   357  
   358  	case FCVTZS, FCVTZU, SCVTF, UCVTF:
   359  		if _, ok := inst.Args[2].(Imm); !ok {
   360  			for i := 1; i >= 0; i-- {
   361  				if r, ok := inst.Args[i].(Reg); ok {
   362  					rno := uint16(r)
   363  					if rno >= uint16(S0) && rno <= uint16(S31) {
   364  						op = fmt.Sprintf("%sS", op)
   365  					} else if rno >= uint16(D0) && rno <= uint16(D31) {
   366  						op = fmt.Sprintf("%sD", op)
   367  					} else if rno <= uint16(WZR) {
   368  						op += "W"
   369  					}
   370  				}
   371  			}
   372  		}
   373  
   374  	case FMOV:
   375  		for i := 0; i <= 1; i++ {
   376  			if r, ok := inst.Args[i].(Reg); ok {
   377  				rno := uint16(r)
   378  				if rno >= uint16(S0) && rno <= uint16(S31) {
   379  					op = fmt.Sprintf("%sS", op)
   380  					break
   381  				} else if rno >= uint16(D0) && rno <= uint16(D31) {
   382  					op = fmt.Sprintf("%sD", op)
   383  					break
   384  				}
   385  			}
   386  		}
   387  
   388  	case SYSL:
   389  		op1 := int(inst.Args[1].(Imm).Imm)
   390  		cn := int(inst.Args[2].(Imm_c))
   391  		cm := int(inst.Args[3].(Imm_c))
   392  		op2 := int(inst.Args[4].(Imm).Imm)
   393  		sysregno := int32(op1<<16 | cn<<12 | cm<<8 | op2<<5)
   394  		args[1] = fmt.Sprintf("$%d", sysregno)
   395  		return op + " " + args[1] + ", " + args[0]
   396  
   397  	case CBNZ, CBZ:
   398  		if r, ok := inst.Args[0].(Reg); ok {
   399  			rno := uint16(r)
   400  			if rno <= uint16(WZR) {
   401  				op += "W"
   402  			}
   403  		}
   404  		args[0], args[1] = args[1], args[0]
   405  
   406  	case ADR, ADRP:
   407  		addr := int64(inst.Args[1].(PCRel))
   408  		args[1] = fmt.Sprintf("%d(PC)", addr)
   409  
   410  	case MSR:
   411  		args[0] = inst.Args[0].String()
   412  
   413  	case ST1:
   414  		op = fmt.Sprintf("V%s", op) + suffix
   415  		args[0], args[1] = args[1], args[0]
   416  
   417  	case LD1:
   418  		op = fmt.Sprintf("V%s", op) + suffix
   419  
   420  	case UMOV:
   421  		op = "VMOV"
   422  	case NOP:
   423  		op = "NOOP"
   424  
   425  	default:
   426  		index := sort.SearchStrings(noSuffixOpSet, op)
   427  		if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
   428  			rno := -1
   429  			switch a := inst.Args[0].(type) {
   430  			case Reg:
   431  				rno = int(a)
   432  			case RegSP:
   433  				rno = int(a)
   434  			case RegisterWithArrangement:
   435  				op = fmt.Sprintf("V%s", op)
   436  			}
   437  
   438  			if rno >= int(B0) && rno <= int(Q31) && !strings.HasPrefix(op, "F") {
   439  				op = fmt.Sprintf("V%s", op)
   440  			}
   441  			if rno >= 0 && rno <= int(WZR) {
   442  				// Add "w" to opcode suffix.
   443  				op += "W"
   444  			}
   445  		}
   446  		op = op + suffix
   447  	}
   448  
   449  	// conditional instructions, replace args.
   450  	if _, ok := inst.Args[3].(Cond); ok {
   451  		if _, ok := inst.Args[2].(Reg); ok {
   452  			args[1], args[2] = args[2], args[1]
   453  		} else {
   454  			args[0], args[2] = args[2], args[0]
   455  		}
   456  	}
   457  	// Reverse args, placing dest last.
   458  	for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   459  		args[i], args[j] = args[j], args[i]
   460  	}
   461  
   462  	if args != nil {
   463  		op += " " + strings.Join(args, ", ")
   464  	}
   465  
   466  	return op
   467  }
   468  
   469  // No need add "W" to opcode suffix.
   470  // Opcode must be inserted in ascending order.
   471  var noSuffixOpSet = strings.Fields(`
   472  AESD
   473  AESE
   474  AESIMC
   475  AESMC
   476  CRC32B
   477  CRC32CB
   478  CRC32CH
   479  CRC32CW
   480  CRC32CX
   481  CRC32H
   482  CRC32W
   483  CRC32X
   484  LDARB
   485  LDARH
   486  LDAXRB
   487  LDAXRH
   488  LDTRH
   489  LDXRB
   490  LDXRH
   491  SHA1C
   492  SHA1H
   493  SHA1M
   494  SHA1P
   495  SHA1SU0
   496  SHA1SU1
   497  SHA256H
   498  SHA256H2
   499  SHA256SU0
   500  SHA256SU1
   501  `)
   502  
   503  // floating point instructions without "F" prefix.
   504  var fOpsWithoutFPrefix = map[Op]bool{
   505  	LDP: true,
   506  	STP: true,
   507  }
   508  
   509  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   510  	switch a := arg.(type) {
   511  	case Imm:
   512  		return fmt.Sprintf("$%d", uint32(a.Imm))
   513  
   514  	case Imm64:
   515  		return fmt.Sprintf("$%d", int64(a.Imm))
   516  
   517  	case ImmShift:
   518  		if a.shift == 0 {
   519  			return fmt.Sprintf("$%d", a.imm)
   520  		}
   521  		return fmt.Sprintf("$(%d<<%d)", a.imm, a.shift)
   522  
   523  	case PCRel:
   524  		addr := int64(pc) + int64(a)
   525  		if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
   526  			return fmt.Sprintf("%s(SB)", s)
   527  		}
   528  		return fmt.Sprintf("%d(PC)", a/4)
   529  
   530  	case Reg:
   531  		regenum := uint16(a)
   532  		regno := uint16(a) & 31
   533  
   534  		if regenum >= uint16(B0) && regenum <= uint16(Q31) {
   535  			if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") || fOpsWithoutFPrefix[inst.Op] {
   536  				// FP registers are the same ones as SIMD registers
   537  				// Print Fn for scalar variant to align with assembler (e.g., FCVT, SCVTF, UCVTF, etc.)
   538  				return fmt.Sprintf("F%d", regno)
   539  			} else {
   540  				// Print Vn to align with assembler (e.g., SHA256H)
   541  				return fmt.Sprintf("V%d", regno)
   542  			}
   543  
   544  		}
   545  		if regno == 31 {
   546  			return "ZR"
   547  		}
   548  		return fmt.Sprintf("R%d", regno)
   549  
   550  	case RegSP:
   551  		regno := uint16(a) & 31
   552  		if regno == 31 {
   553  			return "RSP"
   554  		}
   555  		return fmt.Sprintf("R%d", regno)
   556  
   557  	case RegExtshiftAmount:
   558  		reg := ""
   559  		regno := uint16(a.reg) & 31
   560  		if regno == 31 {
   561  			reg = "ZR"
   562  		} else {
   563  			reg = fmt.Sprintf("R%d", uint16(a.reg)&31)
   564  		}
   565  		extshift := ""
   566  		amount := ""
   567  		if a.extShift != ExtShift(0) {
   568  			switch a.extShift {
   569  			default:
   570  				extshift = "." + a.extShift.String()
   571  
   572  			case lsl:
   573  				extshift = "<<"
   574  				amount = fmt.Sprintf("%d", a.amount)
   575  				return reg + extshift + amount
   576  
   577  			case lsr:
   578  				extshift = ">>"
   579  				amount = fmt.Sprintf("%d", a.amount)
   580  				return reg + extshift + amount
   581  
   582  			case asr:
   583  				extshift = "->"
   584  				amount = fmt.Sprintf("%d", a.amount)
   585  				return reg + extshift + amount
   586  			case ror:
   587  				extshift = "@>"
   588  				amount = fmt.Sprintf("%d", a.amount)
   589  				return reg + extshift + amount
   590  			}
   591  			if a.amount != 0 {
   592  				amount = fmt.Sprintf("<<%d", a.amount)
   593  			}
   594  		}
   595  		return reg + extshift + amount
   596  
   597  	case MemImmediate:
   598  		off := ""
   599  		base := ""
   600  		regno := uint16(a.Base) & 31
   601  		if regno == 31 {
   602  			base = "(RSP)"
   603  		} else {
   604  			base = fmt.Sprintf("(R%d)", regno)
   605  		}
   606  		if a.imm != 0 && a.Mode != AddrPostReg {
   607  			off = fmt.Sprintf("%d", a.imm)
   608  		} else if a.Mode == AddrPostReg {
   609  			postR := fmt.Sprintf("(R%d)", a.imm)
   610  			return base + postR
   611  		}
   612  		return off + base
   613  
   614  	case MemExtend:
   615  		base := ""
   616  		index := ""
   617  		indexreg := ""
   618  		regno := uint16(a.Base) & 31
   619  		if regno == 31 {
   620  			base = "(RSP)"
   621  		} else {
   622  			base = fmt.Sprintf("(R%d)", regno)
   623  		}
   624  		regno = uint16(a.Index) & 31
   625  		if regno == 31 {
   626  			indexreg = "ZR"
   627  		} else {
   628  			indexreg = fmt.Sprintf("R%d", regno)
   629  		}
   630  
   631  		if a.Extend == lsl {
   632  			// Refer to ARM reference manual, for byte load/store(register), the index
   633  			// shift amount must be 0, encoded in "S" as 0 if omitted, or as 1 if present.
   634  			// a.Amount indicates the index shift amount, encoded in "S" field.
   635  			// a.ShiftMustBeZero is set true indicates the index shift amount must be 0.
   636  			// When a.ShiftMustBeZero is true, GNU syntax prints "[Xn, Xm lsl #0]" if "S"
   637  			// equals to 1, or prints "[Xn, Xm]" if "S" equals to 0.
   638  			if a.Amount != 0 && !a.ShiftMustBeZero {
   639  				index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
   640  			} else if a.ShiftMustBeZero && a.Amount == 1 {
   641  				// When a.ShiftMustBeZero is ture, Go syntax prints "(Rm<<0)" if "a.Amount"
   642  				// equals to 1.
   643  				index = fmt.Sprintf("(%s<<0)", indexreg)
   644  			} else {
   645  				index = fmt.Sprintf("(%s)", indexreg)
   646  			}
   647  		} else {
   648  			if a.Amount != 0 && !a.ShiftMustBeZero {
   649  				index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
   650  			} else {
   651  				index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
   652  			}
   653  		}
   654  
   655  		return base + index
   656  
   657  	case Cond:
   658  		switch arg.String() {
   659  		case "CS":
   660  			return "HS"
   661  		case "CC":
   662  			return "LO"
   663  		}
   664  
   665  	case Imm_clrex:
   666  		return fmt.Sprintf("$%d", uint32(a))
   667  
   668  	case Imm_dcps:
   669  		return fmt.Sprintf("$%d", uint32(a))
   670  
   671  	case Imm_option:
   672  		return fmt.Sprintf("$%d", uint8(a))
   673  
   674  	case Imm_hint:
   675  		return fmt.Sprintf("$%d", uint8(a))
   676  
   677  	case Imm_fp:
   678  		var s, pre, numerator, denominator int16
   679  		var result float64
   680  		if a.s == 0 {
   681  			s = 1
   682  		} else {
   683  			s = -1
   684  		}
   685  		pre = s * int16(16+a.pre)
   686  		if a.exp > 0 {
   687  			numerator = (pre << uint8(a.exp))
   688  			denominator = 16
   689  		} else {
   690  			numerator = pre
   691  			denominator = (16 << uint8(-1*a.exp))
   692  		}
   693  		result = float64(numerator) / float64(denominator)
   694  		return strings.TrimRight(fmt.Sprintf("$%f", result), "0")
   695  
   696  	case RegisterWithArrangement:
   697  		result := a.r.String()
   698  		arrange := a.a.String()
   699  		c := []rune(arrange)
   700  		switch len(c) {
   701  		case 3:
   702  			c[1], c[2] = c[2], c[1] // .8B -> .B8
   703  		case 4:
   704  			c[1], c[2], c[3] = c[3], c[1], c[2] // 16B -> B16
   705  		}
   706  		arrange = string(c)
   707  		result += arrange
   708  		if a.cnt > 0 {
   709  			result = "[" + result
   710  			for i := 1; i < int(a.cnt); i++ {
   711  				cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
   712  				result += ", " + cur.String() + arrange
   713  			}
   714  			result += "]"
   715  		}
   716  		return result
   717  
   718  	case RegisterWithArrangementAndIndex:
   719  		result := a.r.String()
   720  		arrange := a.a.String()
   721  		result += arrange
   722  		if a.cnt > 1 {
   723  			result = "[" + result
   724  			for i := 1; i < int(a.cnt); i++ {
   725  				cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
   726  				result += ", " + cur.String() + arrange
   727  			}
   728  			result += "]"
   729  		}
   730  		return fmt.Sprintf("%s[%d]", result, a.index)
   731  
   732  	case Systemreg:
   733  		return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
   734  
   735  	case Imm_prfop:
   736  		if strings.Contains(a.String(), "#") {
   737  			return fmt.Sprintf("$%d", a)
   738  		}
   739  	}
   740  
   741  	return strings.ToUpper(arg.String())
   742  }
   743  

View as plain text