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  	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  
    41  	case AMOADD_D, AMOADD_D_AQ, AMOADD_D_RL, AMOADD_D_AQRL, AMOADD_W, AMOADD_W_AQ,
    42  		AMOADD_W_RL, AMOADD_W_AQRL, AMOAND_D, AMOAND_D_AQ, AMOAND_D_RL, AMOAND_D_AQRL,
    43  		AMOAND_W, AMOAND_W_AQ, AMOAND_W_RL, AMOAND_W_AQRL, AMOMAXU_D, AMOMAXU_D_AQ,
    44  		AMOMAXU_D_RL, AMOMAXU_D_AQRL, AMOMAXU_W, AMOMAXU_W_AQ, AMOMAXU_W_RL, AMOMAXU_W_AQRL,
    45  		AMOMAX_D, AMOMAX_D_AQ, AMOMAX_D_RL, AMOMAX_D_AQRL, AMOMAX_W, AMOMAX_W_AQ, AMOMAX_W_RL,
    46  		AMOMAX_W_AQRL, AMOMINU_D, AMOMINU_D_AQ, AMOMINU_D_RL, AMOMINU_D_AQRL, AMOMINU_W,
    47  		AMOMINU_W_AQ, AMOMINU_W_RL, AMOMINU_W_AQRL, AMOMIN_D, AMOMIN_D_AQ, AMOMIN_D_RL,
    48  		AMOMIN_D_AQRL, AMOMIN_W, AMOMIN_W_AQ, AMOMIN_W_RL, AMOMIN_W_AQRL, AMOOR_D, AMOOR_D_AQ,
    49  		AMOOR_D_RL, AMOOR_D_AQRL, AMOOR_W, AMOOR_W_AQ, AMOOR_W_RL, AMOOR_W_AQRL, AMOSWAP_D,
    50  		AMOSWAP_D_AQ, AMOSWAP_D_RL, AMOSWAP_D_AQRL, AMOSWAP_W, AMOSWAP_W_AQ, AMOSWAP_W_RL,
    51  		AMOSWAP_W_AQRL, AMOXOR_D, AMOXOR_D_AQ, AMOXOR_D_RL, AMOXOR_D_AQRL, AMOXOR_W,
    52  		AMOXOR_W_AQ, AMOXOR_W_RL, AMOXOR_W_AQRL, SC_D, SC_D_AQ, SC_D_RL, SC_D_AQRL,
    53  		SC_W, SC_W_AQ, SC_W_RL, SC_W_AQRL:
    54  		// Atomic instructions have special operand order.
    55  		args[2], args[1] = args[1], args[2]
    56  
    57  	case ADDI:
    58  		if inst.Args[2].(Simm).Imm == 0 {
    59  			op = "MOV"
    60  			args = args[:len(args)-1]
    61  		}
    62  
    63  	case ADDIW:
    64  		if inst.Args[2].(Simm).Imm == 0 {
    65  			op = "MOVW"
    66  			args = args[:len(args)-1]
    67  		}
    68  
    69  	case ANDI:
    70  		if inst.Args[2].(Simm).Imm == 255 {
    71  			op = "MOVBU"
    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  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
    82  			args[i], args[j] = args[j], args[i]
    83  		}
    84  
    85  	case BGE:
    86  		if inst.Args[1].(Reg) == X0 {
    87  			op = "BGEZ"
    88  			args[1] = args[2]
    89  			args = args[:len(args)-1]
    90  		}
    91  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
    92  			args[i], args[j] = args[j], args[i]
    93  		}
    94  
    95  	case BLT:
    96  		if inst.Args[1].(Reg) == X0 {
    97  			op = "BLTZ"
    98  			args[1] = args[2]
    99  			args = args[:len(args)-1]
   100  		}
   101  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   102  			args[i], args[j] = args[j], args[i]
   103  		}
   104  
   105  	case BNE:
   106  		if inst.Args[1].(Reg) == X0 {
   107  			op = "BNEZ"
   108  			args[1] = args[2]
   109  			args = args[:len(args)-1]
   110  		}
   111  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   112  			args[i], args[j] = args[j], args[i]
   113  		}
   114  
   115  	case BLTU, BGEU:
   116  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   117  			args[i], args[j] = args[j], args[i]
   118  		}
   119  
   120  	case CSRRW:
   121  		switch inst.Args[1].(CSR) {
   122  		case FCSR:
   123  			op = "FSCSR"
   124  			args[1] = args[2]
   125  			args = args[:len(args)-1]
   126  		case FFLAGS:
   127  			op = "FSFLAGS"
   128  			args[1] = args[2]
   129  			args = args[:len(args)-1]
   130  		case FRM:
   131  			op = "FSRM"
   132  			args[1] = args[2]
   133  			args = args[:len(args)-1]
   134  		case CYCLE:
   135  			if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
   136  				op = "UNIMP"
   137  				args = nil
   138  			}
   139  		}
   140  
   141  	case CSRRS:
   142  		if inst.Args[2].(Reg) == X0 {
   143  			switch inst.Args[1].(CSR) {
   144  			case FCSR:
   145  				op = "FRCSR"
   146  				args = args[:len(args)-2]
   147  			case FFLAGS:
   148  				op = "FRFLAGS"
   149  				args = args[:len(args)-2]
   150  			case FRM:
   151  				op = "FRRM"
   152  				args = args[:len(args)-2]
   153  			case CYCLE:
   154  				op = "RDCYCLE"
   155  				args = args[:len(args)-2]
   156  			case CYCLEH:
   157  				op = "RDCYCLEH"
   158  				args = args[:len(args)-2]
   159  			case INSTRET:
   160  				op = "RDINSTRET"
   161  				args = args[:len(args)-2]
   162  			case INSTRETH:
   163  				op = "RDINSTRETH"
   164  				args = args[:len(args)-2]
   165  			case TIME:
   166  				op = "RDTIME"
   167  				args = args[:len(args)-2]
   168  			case TIMEH:
   169  				op = "RDTIMEH"
   170  				args = args[:len(args)-2]
   171  			}
   172  		}
   173  
   174  	// Fence instruction in plan9 doesn't have any operands.
   175  	case FENCE:
   176  		args = nil
   177  
   178  	case FMADD_D, FMADD_H, FMADD_Q, FMADD_S, FMSUB_D, FMSUB_H,
   179  		FMSUB_Q, FMSUB_S, FNMADD_D, FNMADD_H, FNMADD_Q, FNMADD_S,
   180  		FNMSUB_D, FNMSUB_H, FNMSUB_Q, FNMSUB_S:
   181  		args[1], args[3] = args[3], args[1]
   182  
   183  	case FSGNJ_S:
   184  		if inst.Args[2] == inst.Args[1] {
   185  			op = "MOVF"
   186  			args = args[:len(args)-1]
   187  		}
   188  
   189  	case FSGNJ_D:
   190  		if inst.Args[2] == inst.Args[1] {
   191  			op = "MOVD"
   192  			args = args[:len(args)-1]
   193  		}
   194  
   195  	case FSGNJX_S:
   196  		if inst.Args[2] == inst.Args[1] {
   197  			op = "FABSS"
   198  			args = args[:len(args)-1]
   199  		}
   200  
   201  	case FSGNJX_D:
   202  		if inst.Args[2] == inst.Args[1] {
   203  			op = "FABSD"
   204  			args = args[:len(args)-1]
   205  		}
   206  
   207  	case FSGNJN_S:
   208  		if inst.Args[2] == inst.Args[1] {
   209  			op = "FNEGS"
   210  			args = args[:len(args)-1]
   211  		}
   212  
   213  	case FSGNJN_D:
   214  		if inst.Args[2] == inst.Args[1] {
   215  			op = "FNESD"
   216  			args = args[:len(args)-1]
   217  		}
   218  
   219  	case LD, SD:
   220  		op = "MOV"
   221  		if inst.Op == SD {
   222  			args[0], args[1] = args[1], args[0]
   223  		}
   224  
   225  	case LB, SB:
   226  		op = "MOVB"
   227  		if inst.Op == SB {
   228  			args[0], args[1] = args[1], args[0]
   229  		}
   230  
   231  	case LH, SH:
   232  		op = "MOVH"
   233  		if inst.Op == SH {
   234  			args[0], args[1] = args[1], args[0]
   235  		}
   236  
   237  	case LW, SW:
   238  		op = "MOVW"
   239  		if inst.Op == SW {
   240  			args[0], args[1] = args[1], args[0]
   241  		}
   242  
   243  	case LBU:
   244  		op = "MOVBU"
   245  
   246  	case LHU:
   247  		op = "MOVHU"
   248  
   249  	case LWU:
   250  		op = "MOVWU"
   251  
   252  	case FLW, FSW:
   253  		op = "MOVF"
   254  		if inst.Op == FLW {
   255  			args[0], args[1] = args[1], args[0]
   256  		}
   257  
   258  	case FLD, FSD:
   259  		op = "MOVD"
   260  		if inst.Op == FLD {
   261  			args[0], args[1] = args[1], args[0]
   262  		}
   263  
   264  	case SUB:
   265  		if inst.Args[1].(Reg) == X0 {
   266  			op = "NEG"
   267  			args[1] = args[2]
   268  			args = args[:len(args)-1]
   269  		}
   270  
   271  	case XORI:
   272  		if inst.Args[2].(Simm).String() == "-1" {
   273  			op = "NOT"
   274  			args = args[:len(args)-1]
   275  		}
   276  
   277  	case SLTIU:
   278  		if inst.Args[2].(Simm).Imm == 1 {
   279  			op = "SEQZ"
   280  			args = args[:len(args)-1]
   281  		}
   282  
   283  	case SLTU:
   284  		if inst.Args[1].(Reg) == X0 {
   285  			op = "SNEZ"
   286  			args[1] = args[2]
   287  			args = args[:len(args)-1]
   288  		}
   289  
   290  	case JAL:
   291  		if inst.Args[0].(Reg) == X0 {
   292  			op = "JMP"
   293  			args[0] = args[1]
   294  			args = args[:len(args)-1]
   295  		} else if inst.Args[0].(Reg) == X1 {
   296  			op = "CALL"
   297  			args[0] = args[1]
   298  			args = args[:len(args)-1]
   299  		} else {
   300  			args[0], args[1] = args[1], args[0]
   301  		}
   302  
   303  	case JALR:
   304  		if inst.Args[0].(Reg) == X0 {
   305  			if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
   306  				op = "RET"
   307  				args = nil
   308  				break
   309  			}
   310  			op = "JMP"
   311  			args[0] = args[1]
   312  			args = args[:len(args)-1]
   313  		} else if inst.Args[0].(Reg) == X1 {
   314  			op = "CALL"
   315  			args[0] = args[1]
   316  			args = args[:len(args)-1]
   317  		} else {
   318  			args[0], args[1] = args[1], args[0]
   319  		}
   320  	}
   321  
   322  	// Reverse args, placing dest last.
   323  	for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   324  		args[i], args[j] = args[j], args[i]
   325  	}
   326  
   327  	// Change to plan9 opcode format
   328  	// Atomic instructions do not have reorder suffix, so remove them
   329  	op = strings.Replace(op, ".AQRL", "", -1)
   330  	op = strings.Replace(op, ".AQ", "", -1)
   331  	op = strings.Replace(op, ".RL", "", -1)
   332  	op = strings.Replace(op, ".", "", -1)
   333  
   334  	if args != nil {
   335  		op += " " + strings.Join(args, ", ")
   336  	}
   337  
   338  	return op
   339  }
   340  
   341  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   342  	switch a := arg.(type) {
   343  	case Uimm:
   344  		return fmt.Sprintf("$%d", uint32(a.Imm))
   345  
   346  	case Simm:
   347  		imm, _ := strconv.Atoi(a.String())
   348  		if a.Width == 13 || a.Width == 21 {
   349  			addr := int64(pc) + int64(imm)
   350  			if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
   351  				return fmt.Sprintf("%s(SB)", s)
   352  			}
   353  			return fmt.Sprintf("%d(PC)", imm/4)
   354  		}
   355  		return fmt.Sprintf("$%d", int32(imm))
   356  
   357  	case Reg:
   358  		if a <= 31 {
   359  			return fmt.Sprintf("X%d", a)
   360  		} else {
   361  			return fmt.Sprintf("F%d", a-32)
   362  		}
   363  
   364  	case RegOffset:
   365  		if a.Ofs.Imm == 0 {
   366  			return fmt.Sprintf("(X%d)", a.OfsReg)
   367  		} else {
   368  			return fmt.Sprintf("%s(X%d)", a.Ofs.String(), a.OfsReg)
   369  		}
   370  
   371  	case AmoReg:
   372  		return fmt.Sprintf("(X%d)", a.reg)
   373  
   374  	default:
   375  		return strings.ToUpper(arg.String())
   376  	}
   377  }
   378  

View as plain text