Source file src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go

     1  // Copyright 2015 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 ppc64asm
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  )
    11  
    12  // GoSyntax returns the Go assembler syntax for the instruction.
    13  // The pc is the program counter of the first instruction, used for expanding
    14  // PC-relative addresses into absolute ones.
    15  // The symname function queries the symbol table for the program
    16  // being disassembled. It returns the name and base address of the symbol
    17  // containing the target, if any; otherwise it returns "", 0.
    18  func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
    19  	if symname == nil {
    20  		symname = func(uint64) (string, uint64) { return "", 0 }
    21  	}
    22  	if inst.Op == 0 && inst.Enc == 0 {
    23  		return "WORD $0"
    24  	} else if inst.Op == 0 {
    25  		return "?"
    26  	}
    27  	var args []string
    28  	for i, a := range inst.Args[:] {
    29  		if a == nil {
    30  			break
    31  		}
    32  		if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
    33  			args = append(args, s)
    34  		}
    35  	}
    36  	var op string
    37  	op = plan9OpMap[inst.Op]
    38  	if op == "" {
    39  		op = strings.ToUpper(inst.Op.String())
    40  		if op[len(op)-1] == '.' {
    41  			op = op[:len(op)-1] + "CC"
    42  		}
    43  	}
    44  	// laid out the instruction
    45  	switch inst.Op {
    46  	default: // dst, sA, sB, ...
    47  		switch len(args) {
    48  		case 0:
    49  			return op
    50  		case 1:
    51  			return fmt.Sprintf("%s %s", op, args[0])
    52  		case 2:
    53  			if inst.Op == COPY || inst.Op == PASTECC {
    54  				return op + " " + args[0] + "," + args[1]
    55  			}
    56  			return op + " " + args[1] + "," + args[0]
    57  		case 3:
    58  			if reverseOperandOrder(inst.Op) {
    59  				return op + " " + args[2] + "," + args[1] + "," + args[0]
    60  			}
    61  		case 4:
    62  			if reverseMiddleOps(inst.Op) {
    63  				return op + " " + args[1] + "," + args[3] + "," + args[2] + "," + args[0]
    64  			}
    65  		}
    66  		args = append(args, args[0])
    67  		return op + " " + strings.Join(args[1:], ",")
    68  	case PASTECC:
    69  		// paste. has two input registers, and an L field, unlike other 3 operand instructions.
    70  		return op + " " + args[0] + "," + args[1] + "," + args[2]
    71  	case SYNC:
    72  		if args[0] == "$1" {
    73  			return "LWSYNC"
    74  		}
    75  		return "HWSYNC"
    76  
    77  	case ISEL:
    78  		return "ISEL " + args[3] + "," + args[1] + "," + args[2] + "," + args[0]
    79  
    80  	// store instructions always have the memory operand at the end, no need to reorder
    81  	// indexed stores handled separately
    82  	case STB, STBU,
    83  		STH, STHU,
    84  		STW, STWU,
    85  		STD, STDU,
    86  		STFD, STFDU,
    87  		STFS, STFSU,
    88  		STQ, HASHST, HASHSTP:
    89  		return op + " " + strings.Join(args, ",")
    90  
    91  	case FCMPU, FCMPO, CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
    92  		crf := int(inst.Args[0].(CondReg) - CR0)
    93  		cmpstr := op + " " + args[1] + "," + args[2]
    94  		if crf != 0 { // print CRx as the final operand if not implied (i.e BF != 0)
    95  			cmpstr += "," + args[0]
    96  		}
    97  		return cmpstr
    98  
    99  	case LIS:
   100  		return "ADDIS $0," + args[1] + "," + args[0]
   101  	// store instructions with index registers
   102  	case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
   103  		STHBRX, STWBRX, STDBRX, STSWX, STFIWX:
   104  		return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
   105  
   106  	case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
   107  		return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
   108  
   109  	case STXVX, STXVD2X, STXVW4X, STXVH8X, STXVB16X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
   110  		return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
   111  
   112  	case STXV:
   113  		return op + " " + args[0] + "," + args[1]
   114  
   115  	case STXVL, STXVLL:
   116  		return op + " " + args[0] + "," + args[1] + "," + args[2]
   117  
   118  	case LWAX, LWAUX, LWZX, LHZX, LBZX, LDX, LHAX, LHAUX, LDARX, LWARX, LHARX, LBARX, LFDX, LFDUX, LFSX, LFSUX, LDBRX, LWBRX, LHBRX, LDUX, LWZUX, LHZUX, LBZUX:
   119  		if args[1] == "0" {
   120  			return op + " (" + args[2] + ")," + args[0]
   121  		}
   122  		return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
   123  
   124  	case LXVX, LXVD2X, LXVW4X, LXVH8X, LXVB16X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
   125  		return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
   126  
   127  	case LXV:
   128  		return op + " " + args[1] + "," + args[0]
   129  
   130  	case LXVL, LXVLL:
   131  		return op + " " + args[1] + "," + args[2] + "," + args[0]
   132  
   133  	case DCBT, DCBTST, DCBZ, DCBST, ICBI:
   134  		if args[0] == "0" || args[0] == "R0" {
   135  			return op + " (" + args[1] + ")"
   136  		}
   137  		return op + " (" + args[1] + ")(" + args[0] + ")"
   138  
   139  	// branch instructions needs additional handling
   140  	case BCLR:
   141  		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   142  			return "RET"
   143  		}
   144  		return op + " " + strings.Join(args, ", ")
   145  	case BC:
   146  		bo := int(inst.Args[0].(Imm))
   147  		bi := int(inst.Args[1].(CondReg) - Cond0LT)
   148  		bcname := condName[((bo&0x8)>>1)|(bi&0x3)]
   149  		if bo&0x17 == 4 { // jump only a CR bit set/unset, no hints (at bits) set.
   150  			if bi >= 4 {
   151  				return fmt.Sprintf("B%s CR%d,%s", bcname, bi>>2, args[2])
   152  			} else {
   153  				return fmt.Sprintf("B%s %s", bcname, args[2])
   154  			}
   155  		}
   156  		return op + " " + strings.Join(args, ",")
   157  	case BCCTR:
   158  		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   159  			return "BR (CTR)"
   160  		}
   161  		return op + " " + strings.Join(args, ", ")
   162  	case BCCTRL:
   163  		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   164  			return "BL (CTR)"
   165  		}
   166  		return op + " " + strings.Join(args, ",")
   167  	case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
   168  		return op + " " + strings.Join(args, ",")
   169  	}
   170  }
   171  
   172  // plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
   173  //
   174  // NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
   175  // of inst, it's ok to modify inst.Args here.
   176  func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
   177  	// special cases for load/store instructions
   178  	if _, ok := arg.(Offset); ok {
   179  		if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
   180  			panic(fmt.Errorf("wrong table: offset not followed by register"))
   181  		}
   182  	}
   183  	switch arg := arg.(type) {
   184  	case Reg:
   185  		if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
   186  			return "0"
   187  		}
   188  		if arg == R30 {
   189  			return "g"
   190  		}
   191  		return strings.ToUpper(arg.String())
   192  	case CondReg:
   193  		// This op is left as its numerical value, not mapped onto CR + condition
   194  		if inst.Op == ISEL {
   195  			return fmt.Sprintf("$%d", (arg - Cond0LT))
   196  		}
   197  		bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
   198  		if arg <= Cond0SO {
   199  			return bit
   200  		} else if arg > Cond0SO && arg <= Cond7SO {
   201  			return fmt.Sprintf("CR%d%s", int(arg-Cond0LT)/4, bit)
   202  		} else {
   203  			return fmt.Sprintf("CR%d", int(arg-CR0))
   204  		}
   205  	case Imm:
   206  		return fmt.Sprintf("$%d", arg)
   207  	case SpReg:
   208  		switch arg {
   209  		case 8:
   210  			return "LR"
   211  		case 9:
   212  			return "CTR"
   213  		}
   214  		return fmt.Sprintf("SPR(%d)", int(arg))
   215  	case PCRel:
   216  		addr := pc + uint64(int64(arg))
   217  		s, base := symname(addr)
   218  		if s != "" && addr == base {
   219  			return fmt.Sprintf("%s(SB)", s)
   220  		}
   221  		if inst.Op == BL && s != "" && (addr-base) == 8 {
   222  			// When decoding an object built for PIE, a CALL targeting
   223  			// a global entry point will be adjusted to the local entry
   224  			// if any. For now, assume any symname+8 PC is a local call.
   225  			return fmt.Sprintf("%s+%d(SB)", s, addr-base)
   226  		}
   227  		return fmt.Sprintf("%#x", addr)
   228  	case Label:
   229  		return fmt.Sprintf("%#x", int(arg))
   230  	case Offset:
   231  		reg := inst.Args[argIndex+1].(Reg)
   232  		removeArg(inst, argIndex+1)
   233  		if reg == R0 {
   234  			return fmt.Sprintf("%d(0)", int(arg))
   235  		}
   236  		return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
   237  	}
   238  	return fmt.Sprintf("???(%v)", arg)
   239  }
   240  
   241  func reverseMiddleOps(op Op) bool {
   242  	switch op {
   243  	case FMADD, FMADDCC, FMADDS, FMADDSCC, FMSUB, FMSUBCC, FMSUBS, FMSUBSCC, FNMADD, FNMADDCC, FNMADDS, FNMADDSCC, FNMSUB, FNMSUBCC, FNMSUBS, FNMSUBSCC, FSEL, FSELCC:
   244  		return true
   245  	}
   246  	return false
   247  }
   248  
   249  func reverseOperandOrder(op Op) bool {
   250  	switch op {
   251  	// Special case for SUBF, SUBFC: not reversed
   252  	case ADD, ADDC, ADDE, ADDCC, ADDCCC:
   253  		return true
   254  	case MULLW, MULLWCC, MULHW, MULHWCC, MULLD, MULLDCC, MULHD, MULHDCC, MULLWO, MULLWOCC, MULHWU, MULHWUCC, MULLDO, MULLDOCC:
   255  		return true
   256  	case DIVD, DIVDCC, DIVDU, DIVDUCC, DIVDE, DIVDECC, DIVDEU, DIVDEUCC, DIVDO, DIVDOCC, DIVDUO, DIVDUOCC:
   257  		return true
   258  	case MODUD, MODSD, MODUW, MODSW:
   259  		return true
   260  	case FADD, FADDS, FSUB, FSUBS, FMUL, FMULS, FDIV, FDIVS, FMADD, FMADDS, FMSUB, FMSUBS, FNMADD, FNMADDS, FNMSUB, FNMSUBS, FMULSCC:
   261  		return true
   262  	case FADDCC, FADDSCC, FSUBCC, FMULCC, FDIVCC, FDIVSCC:
   263  		return true
   264  	case OR, ORCC, ORC, ORCCC, AND, ANDCC, ANDC, ANDCCC, XOR, XORCC, NAND, NANDCC, EQV, EQVCC, NOR, NORCC:
   265  		return true
   266  	case SLW, SLWCC, SLD, SLDCC, SRW, SRAW, SRWCC, SRAWCC, SRD, SRDCC, SRAD, SRADCC:
   267  		return true
   268  	}
   269  	return false
   270  }
   271  
   272  // revCondMap maps a conditional register bit to its inverse, if possible.
   273  var revCondMap = map[string]string{
   274  	"LT": "GE", "GT": "LE", "EQ": "NE",
   275  }
   276  
   277  // Lookup table to map BI[0:1] and BO[3] to an extended mnemonic for CR ops.
   278  // Bits 0-1 map to a bit with a CR field, and bit 2 selects the inverted (0)
   279  // or regular (1) extended mnemonic.
   280  var condName = []string{
   281  	"GE",
   282  	"LE",
   283  	"NE",
   284  	"NSO",
   285  	"LT",
   286  	"GT",
   287  	"EQ",
   288  	"SO",
   289  }
   290  
   291  // plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
   292  var plan9OpMap = map[Op]string{
   293  	LWARX:     "LWAR",
   294  	LDARX:     "LDAR",
   295  	LHARX:     "LHAR",
   296  	LBARX:     "LBAR",
   297  	LWAX:      "MOVW",
   298  	LHAX:      "MOVH",
   299  	LWAUX:     "MOVWU",
   300  	LHAU:      "MOVHU",
   301  	LHAUX:     "MOVHU",
   302  	LDX:       "MOVD",
   303  	LDUX:      "MOVDU",
   304  	LWZX:      "MOVWZ",
   305  	LWZUX:     "MOVWZU",
   306  	LHZX:      "MOVHZ",
   307  	LHZUX:     "MOVHZU",
   308  	LBZX:      "MOVBZ",
   309  	LBZUX:     "MOVBZU",
   310  	LDBRX:     "MOVDBR",
   311  	LWBRX:     "MOVWBR",
   312  	LHBRX:     "MOVHBR",
   313  	MCRF:      "MOVFL",
   314  	XORI:      "XOR",
   315  	ORI:       "OR",
   316  	ANDICC:    "ANDCC",
   317  	ANDC:      "ANDN",
   318  	ANDCCC:    "ANDNCC",
   319  	ADDEO:     "ADDEV",
   320  	ADDEOCC:   "ADDEVCC",
   321  	ADDO:      "ADDV",
   322  	ADDOCC:    "ADDVCC",
   323  	ADDMEO:    "ADDMEV",
   324  	ADDMEOCC:  "ADDMEVCC",
   325  	ADDCO:     "ADDCV",
   326  	ADDCOCC:   "ADDCVCC",
   327  	ADDZEO:    "ADDZEV",
   328  	ADDZEOCC:  "ADDZEVCC",
   329  	SUBFME:    "SUBME",
   330  	SUBFMECC:  "SUBMECC",
   331  	SUBFZE:    "SUBZE",
   332  	SUBFZECC:  "SUBZECC",
   333  	SUBFZEO:   "SUBZEV",
   334  	SUBFZEOCC: "SUBZEVCC",
   335  	SUBF:      "SUB",
   336  	SUBFC:     "SUBC",
   337  	SUBFCC:    "SUBCC",
   338  	SUBFCCC:   "SUBCCC",
   339  	ORC:       "ORN",
   340  	ORCCC:     "ORNCC",
   341  	MULLWO:    "MULLWV",
   342  	MULLWOCC:  "MULLWVCC",
   343  	MULLDO:    "MULLDV",
   344  	MULLDOCC:  "MULLDVCC",
   345  	DIVDO:     "DIVDV",
   346  	DIVDOCC:   "DIVDVCC",
   347  	DIVDUO:    "DIVDUV",
   348  	DIVDUOCC:  "DIVDUVCC",
   349  	ADDI:      "ADD",
   350  	MULLI:     "MULLD",
   351  	SRADI:     "SRAD",
   352  	STBCXCC:   "STBCCC",
   353  	STWCXCC:   "STWCCC",
   354  	STDCXCC:   "STDCCC",
   355  	LI:        "MOVD",
   356  	LBZ:       "MOVBZ", STB: "MOVB",
   357  	LBZU: "MOVBZU", STBU: "MOVBU",
   358  	LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
   359  	LHZU: "MOVHZU", STHU: "MOVHU",
   360  	LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
   361  	LWZU: "MOVWZU", STWU: "MOVWU",
   362  	LD: "MOVD", STD: "MOVD",
   363  	LDU: "MOVDU", STDU: "MOVDU",
   364  	LFD: "FMOVD", STFD: "FMOVD",
   365  	LFS: "FMOVS", STFS: "FMOVS",
   366  	LFDX: "FMOVD", STFDX: "FMOVD",
   367  	LFDU: "FMOVDU", STFDU: "FMOVDU",
   368  	LFDUX: "FMOVDU", STFDUX: "FMOVDU",
   369  	LFSX: "FMOVS", STFSX: "FMOVS",
   370  	LFSU: "FMOVSU", STFSU: "FMOVSU",
   371  	LFSUX: "FMOVSU", STFSUX: "FMOVSU",
   372  	CMPD: "CMP", CMPDI: "CMP",
   373  	CMPW: "CMPW", CMPWI: "CMPW",
   374  	CMPLD: "CMPU", CMPLDI: "CMPU",
   375  	CMPLW: "CMPWU", CMPLWI: "CMPWU",
   376  	MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
   377  	B:  "BR",
   378  	BL: "CALL",
   379  }
   380  

View as plain text