Source file src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/plan9x.go

     1  // Copyright 2024 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 riscv64asm
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"strconv"
    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  	hasVectorArg := false
    30  	var args []string
    31  	for _, a := range inst.Args {
    32  		if a == nil {
    33  			break
    34  		}
    35  		args = append(args, plan9Arg(&inst, pc, symname, a))
    36  		if r, ok := a.(Reg); ok {
    37  			hasVectorArg = hasVectorArg || (r >= V0 && r <= V31)
    38  		}
    39  	}
    40  
    41  	if hasVectorArg {
    42  		return plan9VectorOp(inst, args)
    43  	}
    44  
    45  	op := inst.Op.String()
    46  
    47  goSyntaxSwitch:
    48  	switch inst.Op {
    49  
    50  	case AMOADD_D, AMOADD_D_AQ, AMOADD_D_RL, AMOADD_D_AQRL, AMOADD_W, AMOADD_W_AQ,
    51  		AMOADD_W_RL, AMOADD_W_AQRL, AMOAND_D, AMOAND_D_AQ, AMOAND_D_RL, AMOAND_D_AQRL,
    52  		AMOAND_W, AMOAND_W_AQ, AMOAND_W_RL, AMOAND_W_AQRL, AMOMAXU_D, AMOMAXU_D_AQ,
    53  		AMOMAXU_D_RL, AMOMAXU_D_AQRL, AMOMAXU_W, AMOMAXU_W_AQ, AMOMAXU_W_RL, AMOMAXU_W_AQRL,
    54  		AMOMAX_D, AMOMAX_D_AQ, AMOMAX_D_RL, AMOMAX_D_AQRL, AMOMAX_W, AMOMAX_W_AQ, AMOMAX_W_RL,
    55  		AMOMAX_W_AQRL, AMOMINU_D, AMOMINU_D_AQ, AMOMINU_D_RL, AMOMINU_D_AQRL, AMOMINU_W,
    56  		AMOMINU_W_AQ, AMOMINU_W_RL, AMOMINU_W_AQRL, AMOMIN_D, AMOMIN_D_AQ, AMOMIN_D_RL,
    57  		AMOMIN_D_AQRL, AMOMIN_W, AMOMIN_W_AQ, AMOMIN_W_RL, AMOMIN_W_AQRL, AMOOR_D, AMOOR_D_AQ,
    58  		AMOOR_D_RL, AMOOR_D_AQRL, AMOOR_W, AMOOR_W_AQ, AMOOR_W_RL, AMOOR_W_AQRL, AMOSWAP_D,
    59  		AMOSWAP_D_AQ, AMOSWAP_D_RL, AMOSWAP_D_AQRL, AMOSWAP_W, AMOSWAP_W_AQ, AMOSWAP_W_RL,
    60  		AMOSWAP_W_AQRL, AMOXOR_D, AMOXOR_D_AQ, AMOXOR_D_RL, AMOXOR_D_AQRL, AMOXOR_W,
    61  		AMOXOR_W_AQ, AMOXOR_W_RL, AMOXOR_W_AQRL, SC_D, SC_D_AQ, SC_D_RL, SC_D_AQRL,
    62  		SC_W, SC_W_AQ, SC_W_RL, SC_W_AQRL:
    63  		// Atomic instructions have special operand order.
    64  		args[2], args[1] = args[1], args[2]
    65  
    66  	case ADDI:
    67  		if inst.Args[2].(Simm).Imm == 0 {
    68  			op = "MOV"
    69  			args = args[:len(args)-1]
    70  		}
    71  
    72  	case ADDIW:
    73  		if inst.Args[2].(Simm).Imm == 0 {
    74  			op = "MOVW"
    75  			args = args[:len(args)-1]
    76  		}
    77  
    78  	case ORI:
    79  		if inst.Args[0].(Reg) == X0 {
    80  			simm := inst.Args[2].(Simm)
    81  			switch simm.Imm & 0b11111 {
    82  			case 0:
    83  				op = "PREFETCHI"
    84  			case 1:
    85  				op = "PREFETCHR"
    86  			case 3:
    87  				op = "PREFETCHW"
    88  			default:
    89  				break goSyntaxSwitch
    90  			}
    91  			// compared to ORI, the lowest 5 bits of simm.Imm in PREFETCH should be zeros
    92  			simm.Imm = simm.Imm &^ 0b11111
    93  			args[0] = plan9Arg(&inst, pc, symname, RegOffset{inst.Args[1].(Reg), simm})
    94  			args = args[:len(args)-2]
    95  		}
    96  
    97  	case ANDI:
    98  		if inst.Args[2].(Simm).Imm == 255 {
    99  			op = "MOVBU"
   100  			args = args[:len(args)-1]
   101  		}
   102  
   103  	case BEQ:
   104  		if inst.Args[1].(Reg) == X0 {
   105  			op = "BEQZ"
   106  			args[1] = args[2]
   107  			args = args[:len(args)-1]
   108  		}
   109  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   110  			args[i], args[j] = args[j], args[i]
   111  		}
   112  
   113  	case BGE:
   114  		if inst.Args[1].(Reg) == X0 {
   115  			op = "BGEZ"
   116  			args[1] = args[2]
   117  			args = args[:len(args)-1]
   118  		}
   119  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   120  			args[i], args[j] = args[j], args[i]
   121  		}
   122  
   123  	case BLT:
   124  		if inst.Args[1].(Reg) == X0 {
   125  			op = "BLTZ"
   126  			args[1] = args[2]
   127  			args = args[:len(args)-1]
   128  		}
   129  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   130  			args[i], args[j] = args[j], args[i]
   131  		}
   132  
   133  	case BNE:
   134  		if inst.Args[1].(Reg) == X0 {
   135  			op = "BNEZ"
   136  			args[1] = args[2]
   137  			args = args[:len(args)-1]
   138  		}
   139  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   140  			args[i], args[j] = args[j], args[i]
   141  		}
   142  
   143  	case BLTU, BGEU:
   144  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   145  			args[i], args[j] = args[j], args[i]
   146  		}
   147  
   148  	case CSRRW:
   149  		switch inst.Args[1].(CSR) {
   150  		case FCSR:
   151  			op = "FSCSR"
   152  			args[1] = args[2]
   153  			args = args[:len(args)-1]
   154  		case FFLAGS:
   155  			op = "FSFLAGS"
   156  			args[1] = args[2]
   157  			args = args[:len(args)-1]
   158  		case FRM:
   159  			op = "FSRM"
   160  			args[1] = args[2]
   161  			args = args[:len(args)-1]
   162  		case CYCLE:
   163  			if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
   164  				op = "UNIMP"
   165  				args = nil
   166  			}
   167  		}
   168  
   169  	case CSRRS:
   170  		if inst.Args[2].(Reg) == X0 {
   171  			switch inst.Args[1].(CSR) {
   172  			case FCSR:
   173  				op = "FRCSR"
   174  				args = args[:len(args)-2]
   175  			case FFLAGS:
   176  				op = "FRFLAGS"
   177  				args = args[:len(args)-2]
   178  			case FRM:
   179  				op = "FRRM"
   180  				args = args[:len(args)-2]
   181  			case CYCLE:
   182  				op = "RDCYCLE"
   183  				args = args[:len(args)-2]
   184  			case CYCLEH:
   185  				op = "RDCYCLEH"
   186  				args = args[:len(args)-2]
   187  			case INSTRET:
   188  				op = "RDINSTRET"
   189  				args = args[:len(args)-2]
   190  			case INSTRETH:
   191  				op = "RDINSTRETH"
   192  				args = args[:len(args)-2]
   193  			case TIME:
   194  				op = "RDTIME"
   195  				args = args[:len(args)-2]
   196  			case TIMEH:
   197  				op = "RDTIMEH"
   198  				args = args[:len(args)-2]
   199  			}
   200  		}
   201  
   202  	case FENCE:
   203  		fm := inst.Enc >> 28
   204  		pred := inst.Args[0].(MemOrder).String()
   205  		succ := inst.Args[1].(MemOrder).String()
   206  		if fm == 0b1000 {
   207  			if pred == "rw" && succ == "rw" {
   208  				return "FENCE.TSO"
   209  			}
   210  			return op
   211  		}
   212  		// PAUSE is encoded as a FENCE instruction with pred=W, succ=0.
   213  		if pred == "w" && succ == "" {
   214  			return "PAUSE"
   215  		}
   216  		if fm != 0 || pred == "" || succ == "" || (pred == "iorw" && succ == "iorw") {
   217  			// We've either got a full fence or a reserved encoding which should be
   218  			// treated as a full fence.
   219  			return op
   220  		}
   221  		args[0], args[1] = args[1], args[0]
   222  
   223  	case FMADD_D, FMADD_H, FMADD_Q, FMADD_S, FMSUB_D, FMSUB_H,
   224  		FMSUB_Q, FMSUB_S, FNMADD_D, FNMADD_H, FNMADD_Q, FNMADD_S,
   225  		FNMSUB_D, FNMSUB_H, FNMSUB_Q, FNMSUB_S:
   226  		args[1], args[3] = args[3], args[1]
   227  
   228  	case FMV_W_X:
   229  		if inst.Args[1].(Reg) == X0 {
   230  			args[1] = "$(0.0)"
   231  		}
   232  		fallthrough
   233  	case FMV_X_W:
   234  		op = "MOVF"
   235  
   236  	case FMV_D_X:
   237  		if inst.Args[1].(Reg) == X0 {
   238  			args[1] = "$(0.0)"
   239  		}
   240  		fallthrough
   241  	case FMV_X_D:
   242  		op = "MOVD"
   243  
   244  	case FSGNJ_S:
   245  		if inst.Args[2] == inst.Args[1] {
   246  			op = "MOVF"
   247  			args = args[:len(args)-1]
   248  		}
   249  
   250  	case FSGNJ_D:
   251  		if inst.Args[2] == inst.Args[1] {
   252  			op = "MOVD"
   253  			args = args[:len(args)-1]
   254  		}
   255  
   256  	case FSGNJX_S:
   257  		if inst.Args[2] == inst.Args[1] {
   258  			op = "FABSS"
   259  			args = args[:len(args)-1]
   260  		}
   261  
   262  	case FSGNJX_D:
   263  		if inst.Args[2] == inst.Args[1] {
   264  			op = "FABSD"
   265  			args = args[:len(args)-1]
   266  		}
   267  
   268  	case FSGNJN_S:
   269  		if inst.Args[2] == inst.Args[1] {
   270  			op = "FNEGS"
   271  			args = args[:len(args)-1]
   272  		}
   273  
   274  	case FSGNJN_D:
   275  		if inst.Args[2] == inst.Args[1] {
   276  			op = "FNESD"
   277  			args = args[:len(args)-1]
   278  		}
   279  
   280  	case LD, SD:
   281  		op = "MOV"
   282  		if inst.Op == SD {
   283  			args[0], args[1] = args[1], args[0]
   284  		}
   285  
   286  	case LB, SB:
   287  		op = "MOVB"
   288  		if inst.Op == SB {
   289  			args[0], args[1] = args[1], args[0]
   290  		}
   291  
   292  	case LH, SH:
   293  		op = "MOVH"
   294  		if inst.Op == SH {
   295  			args[0], args[1] = args[1], args[0]
   296  		}
   297  
   298  	case LW, SW:
   299  		op = "MOVW"
   300  		if inst.Op == SW {
   301  			args[0], args[1] = args[1], args[0]
   302  		}
   303  
   304  	case LBU:
   305  		op = "MOVBU"
   306  
   307  	case LHU:
   308  		op = "MOVHU"
   309  
   310  	case LWU:
   311  		op = "MOVWU"
   312  
   313  	case FLW, FSW:
   314  		op = "MOVF"
   315  		if inst.Op == FSW {
   316  			args[0], args[1] = args[1], args[0]
   317  		}
   318  
   319  	case FLD, FSD:
   320  		op = "MOVD"
   321  		if inst.Op == FSD {
   322  			args[0], args[1] = args[1], args[0]
   323  		}
   324  
   325  	case SUB:
   326  		if inst.Args[1].(Reg) == X0 {
   327  			op = "NEG"
   328  			args[1] = args[2]
   329  			args = args[:len(args)-1]
   330  		}
   331  
   332  	case XORI:
   333  		if inst.Args[2].(Simm).String() == "-1" {
   334  			op = "NOT"
   335  			args = args[:len(args)-1]
   336  		}
   337  
   338  	case SLTIU:
   339  		if inst.Args[2].(Simm).Imm == 1 {
   340  			op = "SEQZ"
   341  			args = args[:len(args)-1]
   342  		}
   343  
   344  	case SLTU:
   345  		if inst.Args[1].(Reg) == X0 {
   346  			op = "SNEZ"
   347  			args[1] = args[2]
   348  			args = args[:len(args)-1]
   349  		}
   350  
   351  	case JAL:
   352  		if inst.Args[0].(Reg) == X0 {
   353  			op = "JMP"
   354  			args[0] = args[1]
   355  			args = args[:len(args)-1]
   356  		} else if inst.Args[0].(Reg) == X1 {
   357  			op = "CALL"
   358  			args[0] = args[1]
   359  			args = args[:len(args)-1]
   360  		} else {
   361  			args[0], args[1] = args[1], args[0]
   362  		}
   363  
   364  	case JALR:
   365  		if inst.Args[0].(Reg) == X0 {
   366  			if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   367  				op = "RET"
   368  				args = nil
   369  				break
   370  			}
   371  			op = "JMP"
   372  			args[0] = args[1]
   373  			args = args[:len(args)-1]
   374  		} else if inst.Args[0].(Reg) == X1 {
   375  			op = "CALL"
   376  			args[0] = args[1]
   377  			args = args[:len(args)-1]
   378  		} else {
   379  			args[0], args[1] = args[1], args[0]
   380  		}
   381  
   382  	case VSETVLI, VSETIVLI:
   383  		args[0], args[1], args[2] = args[2], args[0], args[1]
   384  
   385  	case VSETVL:
   386  		args[0], args[2] = args[2], args[0]
   387  	}
   388  
   389  	// Reverse args, placing dest last.
   390  	for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   391  		args[i], args[j] = args[j], args[i]
   392  	}
   393  
   394  	// Change to plan9 opcode format
   395  	// Atomic instructions do not have reorder suffix, so remove them
   396  	op = strings.Replace(op, ".AQRL", "", -1)
   397  	op = strings.Replace(op, ".AQ", "", -1)
   398  	op = strings.Replace(op, ".RL", "", -1)
   399  	op = strings.Replace(op, ".", "", -1)
   400  
   401  	if args != nil {
   402  		op += " " + strings.Join(args, ", ")
   403  	}
   404  
   405  	return op
   406  }
   407  
   408  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   409  	switch a := arg.(type) {
   410  	case Uimm:
   411  		return fmt.Sprintf("$%d", uint32(a.Imm))
   412  
   413  	case Simm:
   414  		imm, _ := strconv.Atoi(a.String())
   415  		if a.Width == 13 || a.Width == 21 {
   416  			addr := int64(pc) + int64(imm)
   417  			if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
   418  				return fmt.Sprintf("%s(SB)", s)
   419  			}
   420  			return fmt.Sprintf("%d(PC)", imm/4)
   421  		}
   422  		return fmt.Sprintf("$%d", int32(imm))
   423  
   424  	case RegOffset:
   425  		if a.Ofs.Imm == 0 {
   426  			return fmt.Sprintf("(X%d)", a.OfsReg)
   427  		} else {
   428  			return fmt.Sprintf("%s(X%d)", a.Ofs.String(), a.OfsReg)
   429  		}
   430  
   431  	case RegPtr:
   432  		return fmt.Sprintf("(X%d)", a.reg)
   433  
   434  	default:
   435  		return strings.ToUpper(arg.String())
   436  	}
   437  }
   438  
   439  func plan9VectorOp(inst Inst, args []string) string {
   440  	// Instruction is either a vector load, store or an arithmetic
   441  	// operation. We can use the inst.Enc to figure out which. Whatever
   442  	// it is, it has at least one argument.
   443  
   444  	var op string
   445  	rawArgs := inst.Args[:]
   446  
   447  	var mask string
   448  	if inst.Enc&(1<<25) == 0 {
   449  		mask = "V0"
   450  		if !implicitMask(inst.Op) {
   451  			args = args[1:]
   452  			rawArgs = rawArgs[1:]
   453  		}
   454  	}
   455  
   456  	if len(args) > 1 {
   457  		if inst.Enc&0x7f == 0x7 {
   458  			// It's a load
   459  			if len(args) == 3 {
   460  				args[0], args[1] = args[1], args[0]
   461  			}
   462  			op = pseudoRVVLoad(inst.Op)
   463  		} else if inst.Enc&0x7f == 0x27 {
   464  			// It's a store
   465  			if len(args) == 3 {
   466  				args[0], args[1], args[2] = args[2], args[0], args[1]
   467  			} else if len(args) == 2 {
   468  				args[0], args[1] = args[1], args[0]
   469  			}
   470  		} else {
   471  			// It's an arithmetic instruction
   472  
   473  			op, args = pseudoRVVArith(inst.Op, rawArgs, args)
   474  
   475  			if len(args) == 3 && !imaOrFma(inst.Op) {
   476  				args[0], args[1] = args[1], args[0]
   477  			}
   478  		}
   479  	}
   480  
   481  	// The mask is always the penultimate argument
   482  
   483  	if mask != "" {
   484  		args = append(args[:len(args)-1], mask, args[len(args)-1])
   485  	}
   486  
   487  	if op == "" {
   488  		op = inst.Op.String()
   489  	}
   490  
   491  	op = strings.Replace(op, ".", "", -1)
   492  	return op + " " + strings.Join(args, ", ")
   493  }
   494  

View as plain text