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

View as plain text