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  	switch inst.Op {
    33  	case ADDI, ADDIW, ANDI, ORI, SLLI, SLLIW, SRAI, SRAIW, SRLI, SRLIW, XORI:
    34  		if inst.Op == ADDI {
    35  			if inst.Args[1].(Reg) == X0 && inst.Args[0].(Reg) != X0 {
    36  				op = "li"
    37  				args[1] = args[2]
    38  				args = args[:len(args)-1]
    39  				break
    40  			}
    41  
    42  			if inst.Args[2].(Simm).Imm == 0 {
    43  				if inst.Args[0].(Reg) == X0 && inst.Args[1].(Reg) == X0 {
    44  					op = "nop"
    45  					args = nil
    46  				} else {
    47  					op = "mv"
    48  					args = args[:len(args)-1]
    49  				}
    50  			}
    51  		}
    52  
    53  		if inst.Op == ANDI && inst.Args[2].(Simm).Imm == 255 {
    54  			op = "zext.b"
    55  			args = args[:len(args)-1]
    56  		}
    57  
    58  		if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 {
    59  			op = "sext.w"
    60  			args = args[:len(args)-1]
    61  		}
    62  
    63  		if inst.Op == XORI && inst.Args[2].(Simm).String() == "-1" {
    64  			op = "not"
    65  			args = args[:len(args)-1]
    66  		}
    67  
    68  	case ADD:
    69  		if inst.Args[1].(Reg) == X0 {
    70  			op = "mv"
    71  			args[1] = args[2]
    72  			args = args[:len(args)-1]
    73  		}
    74  
    75  	case BEQ:
    76  		if inst.Args[1].(Reg) == X0 {
    77  			op = "beqz"
    78  			args[1] = args[2]
    79  			args = args[:len(args)-1]
    80  		}
    81  
    82  	case BGE:
    83  		if inst.Args[1].(Reg) == X0 {
    84  			op = "bgez"
    85  			args[1] = args[2]
    86  			args = args[:len(args)-1]
    87  		} else if inst.Args[0].(Reg) == X0 {
    88  			op = "blez"
    89  			args[0], args[1] = args[1], args[2]
    90  			args = args[:len(args)-1]
    91  		}
    92  
    93  	case BLT:
    94  		if inst.Args[1].(Reg) == X0 {
    95  			op = "bltz"
    96  			args[1] = args[2]
    97  			args = args[:len(args)-1]
    98  		} else if inst.Args[0].(Reg) == X0 {
    99  			op = "bgtz"
   100  			args[0], args[1] = args[1], args[2]
   101  			args = args[:len(args)-1]
   102  		}
   103  
   104  	case BNE:
   105  		if inst.Args[1].(Reg) == X0 {
   106  			op = "bnez"
   107  			args[1] = args[2]
   108  			args = args[:len(args)-1]
   109  		}
   110  
   111  	case CSRRC:
   112  		if inst.Args[0].(Reg) == X0 {
   113  			op = "csrc"
   114  			args[0], args[1] = args[1], args[2]
   115  			args = args[:len(args)-1]
   116  		}
   117  
   118  	case CSRRCI:
   119  		if inst.Args[0].(Reg) == X0 {
   120  			op = "csrci"
   121  			args[0], args[1] = args[1], args[2]
   122  			args = args[:len(args)-1]
   123  		}
   124  
   125  	case CSRRS:
   126  		if inst.Args[2].(Reg) == X0 {
   127  			switch inst.Args[1].(CSR) {
   128  			case FCSR:
   129  				op = "frcsr"
   130  				args = args[:len(args)-2]
   131  
   132  			case FFLAGS:
   133  				op = "frflags"
   134  				args = args[:len(args)-2]
   135  
   136  			case FRM:
   137  				op = "frrm"
   138  				args = args[:len(args)-2]
   139  
   140  			// rdcycleh, rdinstreth and rdtimeh are RV-32 only instructions.
   141  			// So not included there.
   142  			case CYCLE:
   143  				op = "rdcycle"
   144  				args = args[:len(args)-2]
   145  
   146  			case INSTRET:
   147  				op = "rdinstret"
   148  				args = args[:len(args)-2]
   149  
   150  			case TIME:
   151  				op = "rdtime"
   152  				args = args[:len(args)-2]
   153  
   154  			default:
   155  				op = "csrr"
   156  				args = args[:len(args)-1]
   157  			}
   158  		} else if inst.Args[0].(Reg) == X0 {
   159  			op = "csrs"
   160  			args[0], args[1] = args[1], args[2]
   161  			args = args[:len(args)-1]
   162  		}
   163  
   164  	case CSRRSI:
   165  		if inst.Args[0].(Reg) == X0 {
   166  			op = "csrsi"
   167  			args[0], args[1] = args[1], args[2]
   168  			args = args[:len(args)-1]
   169  		}
   170  
   171  	case CSRRW:
   172  		switch inst.Args[1].(CSR) {
   173  		case FCSR:
   174  			op = "fscsr"
   175  			if inst.Args[0].(Reg) == X0 {
   176  				args[0] = args[2]
   177  				args = args[:len(args)-2]
   178  			} else {
   179  				args[1] = args[2]
   180  				args = args[:len(args)-1]
   181  			}
   182  
   183  		case FFLAGS:
   184  			op = "fsflags"
   185  			if inst.Args[0].(Reg) == X0 {
   186  				args[0] = args[2]
   187  				args = args[:len(args)-2]
   188  			} else {
   189  				args[1] = args[2]
   190  				args = args[:len(args)-1]
   191  			}
   192  
   193  		case FRM:
   194  			op = "fsrm"
   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 CYCLE:
   204  			if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
   205  				op = "unimp"
   206  				args = nil
   207  			}
   208  
   209  		default:
   210  			if inst.Args[0].(Reg) == X0 {
   211  				op = "csrw"
   212  				args[0], args[1] = args[1], args[2]
   213  				args = args[:len(args)-1]
   214  			}
   215  		}
   216  
   217  	case CSRRWI:
   218  		if inst.Args[0].(Reg) == X0 {
   219  			op = "csrwi"
   220  			args[0], args[1] = args[1], args[2]
   221  			args = args[:len(args)-1]
   222  		}
   223  
   224  	// When both pred and succ equals to iorw, the GNU objdump will omit them.
   225  	case FENCE:
   226  		if inst.Args[0].(MemOrder).String() == "iorw" &&
   227  			inst.Args[1].(MemOrder).String() == "iorw" {
   228  			args = nil
   229  		}
   230  
   231  	case FSGNJX_D:
   232  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   233  			op = "fabs.d"
   234  			args = args[:len(args)-1]
   235  		}
   236  
   237  	case FSGNJX_S:
   238  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   239  			op = "fabs.s"
   240  			args = args[:len(args)-1]
   241  		}
   242  
   243  	case FSGNJ_D:
   244  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   245  			op = "fmv.d"
   246  			args = args[:len(args)-1]
   247  		}
   248  
   249  	case FSGNJ_S:
   250  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   251  			op = "fmv.s"
   252  			args = args[:len(args)-1]
   253  		}
   254  
   255  	case FSGNJN_D:
   256  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   257  			op = "fneg.d"
   258  			args = args[:len(args)-1]
   259  		}
   260  
   261  	case FSGNJN_S:
   262  		if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
   263  			op = "fneg.s"
   264  			args = args[:len(args)-1]
   265  		}
   266  
   267  	case JAL:
   268  		if inst.Args[0].(Reg) == X0 {
   269  			op = "j"
   270  			args[0] = args[1]
   271  			args = args[:len(args)-1]
   272  		} else if inst.Args[0].(Reg) == X1 {
   273  			op = "jal"
   274  			args[0] = args[1]
   275  			args = args[:len(args)-1]
   276  		}
   277  
   278  	case JALR:
   279  		if inst.Args[0].(Reg) == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   280  			args[0] = inst.Args[1].(RegOffset).OfsReg.String()
   281  			args = args[:len(args)-1]
   282  		}
   283  
   284  		if inst.Args[0].(Reg) == X0 {
   285  			if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   286  				op = "ret"
   287  				args = nil
   288  			} else if inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   289  				op = "jr"
   290  				args[0] = inst.Args[1].(RegOffset).OfsReg.String()
   291  				args = args[:len(args)-1]
   292  			} else {
   293  				op = "jr"
   294  				args[0] = inst.Args[1].(RegOffset).String()
   295  				args = args[:len(args)-1]
   296  			}
   297  		}
   298  
   299  	case SLTIU:
   300  		if inst.Args[2].(Simm).String() == "1" {
   301  			op = "seqz"
   302  			args = args[:len(args)-1]
   303  		}
   304  
   305  	case SLT:
   306  		if inst.Args[1].(Reg) == X0 {
   307  			op = "sgtz"
   308  			args[1] = args[2]
   309  			args = args[:len(args)-1]
   310  		} else if inst.Args[2].(Reg) == X0 {
   311  			op = "sltz"
   312  			args = args[:len(args)-1]
   313  		}
   314  
   315  	case SLTU:
   316  		if inst.Args[1].(Reg) == X0 {
   317  			op = "snez"
   318  			args[1] = args[2]
   319  			args = args[:len(args)-1]
   320  		}
   321  
   322  	case SUB:
   323  		if inst.Args[1].(Reg) == X0 {
   324  			op = "neg"
   325  			args[1] = args[2]
   326  			args = args[:len(args)-1]
   327  		}
   328  
   329  	case SUBW:
   330  		if inst.Args[1].(Reg) == X0 {
   331  			op = "negw"
   332  			args[1] = args[2]
   333  			args = args[:len(args)-1]
   334  		}
   335  
   336  	case VSETVLI, VSETIVLI:
   337  		args[0], args[2] = args[2], strings.ReplaceAll(args[0], " ", "")
   338  
   339  	case VSETVL:
   340  		args[0], args[2] = args[2], args[0]
   341  	}
   342  
   343  	if args != nil {
   344  		op += " " + strings.Join(args, ",")
   345  	}
   346  	return op
   347  }
   348  
   349  func gnuVectorOp(inst Inst, args []string) string {
   350  	// Instruction is either a vector load, store or an arithmetic
   351  	// operation. We can use the inst.Enc to figure out which. Whatever
   352  	// it is, it has at least one argument.
   353  
   354  	rawArgs := inst.Args[:]
   355  
   356  	var mask string
   357  	var op string
   358  	if inst.Enc&(1<<25) == 0 {
   359  		if implicitMask(inst.Op) {
   360  			mask = "v0"
   361  		} else {
   362  			mask = "v0.t"
   363  			args = args[1:]
   364  			rawArgs = rawArgs[1:]
   365  		}
   366  	}
   367  
   368  	if len(args) > 1 {
   369  		if inst.Enc&0x7f == 0x7 || inst.Enc&0x7f == 0x27 {
   370  			// It's a load or a store
   371  			if len(args) >= 2 {
   372  				args[0], args[len(args)-1] = args[len(args)-1], args[0]
   373  			}
   374  			op = pseudoRVVLoad(inst.Op)
   375  		} else {
   376  			// It's an arithmetic instruction
   377  
   378  			op, args = pseudoRVVArith(inst.Op, rawArgs, args)
   379  
   380  			if len(args) == 3 {
   381  				if imaOrFma(inst.Op) {
   382  					args[0], args[2] = args[2], args[0]
   383  				} else {
   384  					args[0], args[1], args[2] = args[2], args[0], args[1]
   385  				}
   386  			} else if len(args) == 2 {
   387  				args[0], args[1] = args[1], args[0]
   388  			}
   389  		}
   390  	}
   391  
   392  	// The mask is always the last argument
   393  
   394  	if mask != "" {
   395  		args = append(args, mask)
   396  	}
   397  
   398  	if op == "" {
   399  		op = inst.Op.String()
   400  	}
   401  	op = strings.ToLower(op)
   402  
   403  	return op + " " + strings.Join(args, ",")
   404  }
   405  

View as plain text