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

View as plain text