Source file src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.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  	"strings"
     9  )
    10  
    11  // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
    12  // This form typically matches the syntax defined in the RISC-V Instruction Set Manual. See
    13  // https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf
    14  func GNUSyntax(inst Inst) string {
    15  	hasVectorArg := false
    16  	var args []string
    17  	for _, a := range inst.Args {
    18  		if a == nil {
    19  			break
    20  		}
    21  		args = append(args, strings.ToLower(a.String()))
    22  		if r, ok := a.(Reg); ok {
    23  			hasVectorArg = hasVectorArg || (r >= V0 && r <= V31)
    24  		}
    25  	}
    26  
    27  	if hasVectorArg {
    28  		return gnuVectorOp(inst, args)
    29  	}
    30  
    31  	op := strings.ToLower(inst.Op.String())
    32  gnuSyntaxSwitch:
    33  	switch inst.Op {
    34  	case ADDI, ADDIW, ANDI, SLLI, SLLIW, SRAI, SRAIW, SRLI, SRLIW, XORI:
    35  		if inst.Op == ADDI {
    36  			if inst.Args[1].(Reg) == X0 && inst.Args[0].(Reg) != X0 {
    37  				op = "li"
    38  				args[1] = args[2]
    39  				args = args[:len(args)-1]
    40  				break
    41  			}
    42  
    43  			if inst.Args[2].(Simm).Imm == 0 {
    44  				if inst.Args[0].(Reg) == X0 && inst.Args[1].(Reg) == X0 {
    45  					op = "nop"
    46  					args = nil
    47  				} else {
    48  					op = "mv"
    49  					args = args[:len(args)-1]
    50  				}
    51  			}
    52  		}
    53  
    54  		if inst.Op == ANDI && inst.Args[2].(Simm).Imm == 255 {
    55  			op = "zext.b"
    56  			args = args[:len(args)-1]
    57  		}
    58  
    59  		if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 {
    60  			op = "sext.w"
    61  			args = args[:len(args)-1]
    62  		}
    63  
    64  		if inst.Op == XORI && inst.Args[2].(Simm).String() == "-1" {
    65  			op = "not"
    66  			args = args[:len(args)-1]
    67  		}
    68  
    69  	case ORI:
    70  		if inst.Args[0].(Reg) == X0 {
    71  			simm := inst.Args[2].(Simm)
    72  			switch simm.Imm & 0b11111 {
    73  			case 0:
    74  				op = "prefetch.i"
    75  			case 1:
    76  				op = "prefetch.r"
    77  			case 3:
    78  				op = "prefetch.w"
    79  			default:
    80  				break gnuSyntaxSwitch
    81  			}
    82  			// compared to ORI, the lowest 5 bits of simm.Imm in PREFETCH should be zeros
    83  			simm.Imm = simm.Imm &^ 0b11111
    84  			args[0] = RegOffset{inst.Args[1].(Reg), simm}.String()
    85  			args = args[:len(args)-2]
    86  		}
    87  
    88  	case ADD:
    89  		if inst.Args[1].(Reg) == X0 {
    90  			op = "mv"
    91  			args[1] = args[2]
    92  			args = args[:len(args)-1]
    93  		}
    94  
    95  	case BEQ:
    96  		if inst.Args[1].(Reg) == X0 {
    97  			op = "beqz"
    98  			args[1] = args[2]
    99  			args = args[:len(args)-1]
   100  		}
   101  
   102  	case BGE:
   103  		if inst.Args[1].(Reg) == X0 {
   104  			op = "bgez"
   105  			args[1] = args[2]
   106  			args = args[:len(args)-1]
   107  		} else if inst.Args[0].(Reg) == X0 {
   108  			op = "blez"
   109  			args[0], args[1] = args[1], args[2]
   110  			args = args[:len(args)-1]
   111  		}
   112  
   113  	case BLT:
   114  		if inst.Args[1].(Reg) == X0 {
   115  			op = "bltz"
   116  			args[1] = args[2]
   117  			args = args[:len(args)-1]
   118  		} else if inst.Args[0].(Reg) == X0 {
   119  			op = "bgtz"
   120  			args[0], args[1] = args[1], args[2]
   121  			args = args[:len(args)-1]
   122  		}
   123  
   124  	case BNE:
   125  		if inst.Args[1].(Reg) == X0 {
   126  			op = "bnez"
   127  			args[1] = args[2]
   128  			args = args[:len(args)-1]
   129  		}
   130  
   131  	case CSRRC:
   132  		if inst.Args[0].(Reg) == X0 {
   133  			op = "csrc"
   134  			args[0], args[1] = args[1], args[2]
   135  			args = args[:len(args)-1]
   136  		}
   137  
   138  	case CSRRCI:
   139  		if inst.Args[0].(Reg) == X0 {
   140  			op = "csrci"
   141  			args[0], args[1] = args[1], args[2]
   142  			args = args[:len(args)-1]
   143  		}
   144  
   145  	case CSRRS:
   146  		if inst.Args[2].(Reg) == X0 {
   147  			switch inst.Args[1].(CSR) {
   148  			case FCSR:
   149  				op = "frcsr"
   150  				args = args[:len(args)-2]
   151  
   152  			case FFLAGS:
   153  				op = "frflags"
   154  				args = args[:len(args)-2]
   155  
   156  			case FRM:
   157  				op = "frrm"
   158  				args = args[:len(args)-2]
   159  
   160  			// rdcycleh, rdinstreth and rdtimeh are RV-32 only instructions.
   161  			// So not included there.
   162  			case CYCLE:
   163  				op = "rdcycle"
   164  				args = args[:len(args)-2]
   165  
   166  			case INSTRET:
   167  				op = "rdinstret"
   168  				args = args[:len(args)-2]
   169  
   170  			case TIME:
   171  				op = "rdtime"
   172  				args = args[:len(args)-2]
   173  
   174  			default:
   175  				op = "csrr"
   176  				args = args[:len(args)-1]
   177  			}
   178  		} else if inst.Args[0].(Reg) == X0 {
   179  			op = "csrs"
   180  			args[0], args[1] = args[1], args[2]
   181  			args = args[:len(args)-1]
   182  		}
   183  
   184  	case CSRRSI:
   185  		if inst.Args[0].(Reg) == X0 {
   186  			op = "csrsi"
   187  			args[0], args[1] = args[1], args[2]
   188  			args = args[:len(args)-1]
   189  		}
   190  
   191  	case CSRRW:
   192  		switch inst.Args[1].(CSR) {
   193  		case FCSR:
   194  			op = "fscsr"
   195  			if inst.Args[0].(Reg) == X0 {
   196  				args[0] = args[2]
   197  				args = args[:len(args)-2]
   198  			} else {
   199  				args[1] = args[2]
   200  				args = args[:len(args)-1]
   201  			}
   202  
   203  		case FFLAGS:
   204  			op = "fsflags"
   205  			if inst.Args[0].(Reg) == X0 {
   206  				args[0] = args[2]
   207  				args = args[:len(args)-2]
   208  			} else {
   209  				args[1] = args[2]
   210  				args = args[:len(args)-1]
   211  			}
   212  
   213  		case FRM:
   214  			op = "fsrm"
   215  			if inst.Args[0].(Reg) == X0 {
   216  				args[0] = args[2]
   217  				args = args[:len(args)-2]
   218  			} else {
   219  				args[1] = args[2]
   220  				args = args[:len(args)-1]
   221  			}
   222  
   223  		case CYCLE:
   224  			if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
   225  				op = "unimp"
   226  				args = nil
   227  			}
   228  
   229  		default:
   230  			if inst.Args[0].(Reg) == X0 {
   231  				op = "csrw"
   232  				args[0], args[1] = args[1], args[2]
   233  				args = args[:len(args)-1]
   234  			}
   235  		}
   236  
   237  	case CSRRWI:
   238  		if inst.Args[0].(Reg) == X0 {
   239  			op = "csrwi"
   240  			args[0], args[1] = args[1], args[2]
   241  			args = args[:len(args)-1]
   242  		}
   243  
   244  	case FENCE:
   245  		fm := inst.Enc >> 28
   246  		pred := inst.Args[0].(MemOrder).String()
   247  		succ := inst.Args[1].(MemOrder).String()
   248  		if fm == 0b1000 {
   249  			if pred == "rw" && succ == "rw" {
   250  				return "fence.tso"
   251  			}
   252  			return op
   253  		}
   254  		// PAUSE is encoded as a FENCE instruction with pred=W, succ=0.
   255  		if pred == "w" && succ == "" {
   256  			return "pause"
   257  		}
   258  		if fm != 0 || pred == "" || succ == "" || (pred == "iorw" && succ == "iorw") {
   259  			// We've either got a full fence or a reserved encoding which should be
   260  			// treated as a full fence. When both pred and succ equals to iorw, GNU
   261  			// objdump will omit them.
   262  			return op
   263  		}
   264  
   265  	case FSGNJX_D:
   266  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   267  			op = "fabs.d"
   268  			args = args[:len(args)-1]
   269  		}
   270  
   271  	case FSGNJX_S:
   272  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   273  			op = "fabs.s"
   274  			args = args[:len(args)-1]
   275  		}
   276  
   277  	case FSGNJ_D:
   278  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   279  			op = "fmv.d"
   280  			args = args[:len(args)-1]
   281  		}
   282  
   283  	case FSGNJ_S:
   284  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   285  			op = "fmv.s"
   286  			args = args[:len(args)-1]
   287  		}
   288  
   289  	case FSGNJN_D:
   290  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   291  			op = "fneg.d"
   292  			args = args[:len(args)-1]
   293  		}
   294  
   295  	case FSGNJN_S:
   296  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   297  			op = "fneg.s"
   298  			args = args[:len(args)-1]
   299  		}
   300  
   301  	case JAL:
   302  		if inst.Args[0].(Reg) == X0 {
   303  			op = "j"
   304  			args[0] = args[1]
   305  			args = args[:len(args)-1]
   306  		} else if inst.Args[0].(Reg) == X1 {
   307  			op = "jal"
   308  			args[0] = args[1]
   309  			args = args[:len(args)-1]
   310  		}
   311  
   312  	case JALR:
   313  		if inst.Args[0].(Reg) == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   314  			args[0] = inst.Args[1].(RegOffset).OfsReg.String()
   315  			args = args[:len(args)-1]
   316  		}
   317  
   318  		if inst.Args[0].(Reg) == X0 {
   319  			if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   320  				op = "ret"
   321  				args = nil
   322  			} else if inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   323  				op = "jr"
   324  				args[0] = inst.Args[1].(RegOffset).OfsReg.String()
   325  				args = args[:len(args)-1]
   326  			} else {
   327  				op = "jr"
   328  				args[0] = inst.Args[1].(RegOffset).String()
   329  				args = args[:len(args)-1]
   330  			}
   331  		}
   332  
   333  	case SLTIU:
   334  		if inst.Args[2].(Simm).String() == "1" {
   335  			op = "seqz"
   336  			args = args[:len(args)-1]
   337  		}
   338  
   339  	case SLT:
   340  		if inst.Args[1].(Reg) == X0 {
   341  			op = "sgtz"
   342  			args[1] = args[2]
   343  			args = args[:len(args)-1]
   344  		} else if inst.Args[2].(Reg) == X0 {
   345  			op = "sltz"
   346  			args = args[:len(args)-1]
   347  		}
   348  
   349  	case SLTU:
   350  		if inst.Args[1].(Reg) == X0 {
   351  			op = "snez"
   352  			args[1] = args[2]
   353  			args = args[:len(args)-1]
   354  		}
   355  
   356  	case SUB:
   357  		if inst.Args[1].(Reg) == X0 {
   358  			op = "neg"
   359  			args[1] = args[2]
   360  			args = args[:len(args)-1]
   361  		}
   362  
   363  	case SUBW:
   364  		if inst.Args[1].(Reg) == X0 {
   365  			op = "negw"
   366  			args[1] = args[2]
   367  			args = args[:len(args)-1]
   368  		}
   369  
   370  	case VSETVLI, VSETIVLI:
   371  		args[0], args[2] = args[2], strings.ReplaceAll(args[0], " ", "")
   372  
   373  	case VSETVL:
   374  		args[0], args[2] = args[2], args[0]
   375  	}
   376  
   377  	if args != nil {
   378  		op += " " + strings.Join(args, ",")
   379  	}
   380  	return op
   381  }
   382  
   383  func gnuVectorOp(inst Inst, args []string) string {
   384  	// Instruction is either a vector load, store or an arithmetic
   385  	// operation. We can use the inst.Enc to figure out which. Whatever
   386  	// it is, it has at least one argument.
   387  
   388  	rawArgs := inst.Args[:]
   389  
   390  	var mask string
   391  	var op string
   392  	if inst.Enc&(1<<25) == 0 {
   393  		if implicitMask(inst.Op) {
   394  			mask = "v0"
   395  		} else {
   396  			mask = "v0.t"
   397  			args = args[1:]
   398  			rawArgs = rawArgs[1:]
   399  		}
   400  	}
   401  
   402  	if len(args) > 1 {
   403  		if inst.Enc&0x7f == 0x7 || inst.Enc&0x7f == 0x27 {
   404  			// It's a load or a store
   405  			if len(args) >= 2 {
   406  				args[0], args[len(args)-1] = args[len(args)-1], args[0]
   407  			}
   408  			op = pseudoRVVLoad(inst.Op)
   409  		} else {
   410  			// It's an arithmetic instruction
   411  
   412  			op, args = pseudoRVVArith(inst.Op, rawArgs, args)
   413  
   414  			if len(args) == 3 {
   415  				if imaOrFma(inst.Op) {
   416  					args[0], args[2] = args[2], args[0]
   417  				} else {
   418  					args[0], args[1], args[2] = args[2], args[0], args[1]
   419  				}
   420  			} else if len(args) == 2 {
   421  				args[0], args[1] = args[1], args[0]
   422  			}
   423  		}
   424  	}
   425  
   426  	// The mask is always the last argument
   427  
   428  	if mask != "" {
   429  		args = append(args, mask)
   430  	}
   431  
   432  	if op == "" {
   433  		op = inst.Op.String()
   434  	}
   435  	op = strings.ToLower(op)
   436  
   437  	return op + " " + strings.Join(args, ",")
   438  }
   439  

View as plain text