...

Source file src/pkg/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				// In the case for some BC instructions, a CondReg arg has
    34				// both the CR and the branch condition encoded in its value.
    35				// plan9Arg will return a string with the string representation
    36				// of these values separated by a blank that will be treated
    37				// as 2 args from this point on.
    38				if strings.IndexByte(s, ' ') > 0 {
    39					t := strings.Split(s, " ")
    40					args = append(args, t[0])
    41					args = append(args, t[1])
    42				} else {
    43					args = append(args, s)
    44				}
    45			}
    46		}
    47		var op string
    48		op = plan9OpMap[inst.Op]
    49		if op == "" {
    50			op = strings.ToUpper(inst.Op.String())
    51			if op[len(op)-1] == '.' {
    52				op = op[:len(op)-1] + "CC"
    53			}
    54		}
    55		// laid out the instruction
    56		switch inst.Op {
    57		default: // dst, sA, sB, ...
    58			if len(args) == 0 {
    59				return op
    60			} else if len(args) == 1 {
    61				return fmt.Sprintf("%s %s", op, args[0])
    62			}
    63			args = append(args, args[0])
    64			return op + " " + strings.Join(args[1:], ",")
    65		case SYNC:
    66			if args[0] == "$1" {
    67				return "LWSYNC"
    68			}
    69			return "HWSYNC"
    70	
    71		case ISEL:
    72			return "ISEL " + args[3] + "," + args[1] + "," + args[2] + "," + args[0]
    73	
    74		// store instructions always have the memory operand at the end, no need to reorder
    75		// indexed stores handled separately
    76		case STB, STBU,
    77			STH, STHU,
    78			STW, STWU,
    79			STD, STDU,
    80			STQ:
    81			return op + " " + strings.Join(args, ",")
    82	
    83		case CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
    84			if len(args) == 2 {
    85				return op + " " + args[0] + "," + args[1]
    86			} else if len(args) == 3 {
    87				return op + " " + args[0] + "," + args[1] + "," + args[2]
    88			}
    89			return op + " " + args[0] + " ??"
    90	
    91		case LIS:
    92			return "ADDIS $0," + args[1] + "," + args[0]
    93		// store instructions with index registers
    94		case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
    95			STHBRX, STWBRX, STDBRX, STSWX, STFSX, STFSUX, STFDX, STFDUX, STFIWX, STFDPX:
    96			return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
    97	
    98		case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
    99			return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
   100	
   101		case STXVD2X, STXVW4X:
   102			return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
   103	
   104		// load instructions with index registers
   105		case LBZX, LBZUX, LHZX, LHZUX, LWZX, LWZUX, LDX, LDUX,
   106			LHBRX, LWBRX, LDBRX, LSWX, LFSX, LFSUX, LFDX, LFDUX, LFIWAX, LFIWZX:
   107			return "MOV" + op[1:len(op)-1] + " (" + args[2] + ")(" + args[1] + ")," + args[0]
   108	
   109		case LDARX, LWARX, LHARX, LBARX:
   110			return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
   111	
   112		case LXVD2X, LXVW4X:
   113			return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
   114	
   115		case DCBT, DCBTST, DCBZ, DCBST:
   116			return op + " (" + args[1] + ")"
   117	
   118		// branch instructions needs additional handling
   119		case BCLR:
   120			if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   121				return "RET"
   122			}
   123			return op + " " + strings.Join(args, ", ")
   124		case BC:
   125			if int(inst.Args[0].(Imm))&0x1c == 12 { // jump on cond bit set
   126				if len(args) == 4 {
   127					return fmt.Sprintf("B%s %s,%s", args[1], args[2], args[3])
   128				}
   129				return fmt.Sprintf("B%s %s", args[1], args[2])
   130			} else if int(inst.Args[0].(Imm))&0x1c == 4 && revCondMap[args[1]] != "" { // jump on cond bit not set
   131				if len(args) == 4 {
   132					return fmt.Sprintf("B%s %s,%s", revCondMap[args[1]], args[2], args[3])
   133				}
   134				return fmt.Sprintf("B%s %s", revCondMap[args[1]], args[2])
   135			}
   136			return op + " " + strings.Join(args, ",")
   137		case BCCTR:
   138			if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   139				return "BR (CTR)"
   140			}
   141			return op + " " + strings.Join(args, ", ")
   142		case BCCTRL:
   143			if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
   144				return "BL (CTR)"
   145			}
   146			return op + " " + strings.Join(args, ",")
   147		case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
   148			return op + " " + strings.Join(args, ",")
   149		}
   150	}
   151	
   152	// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
   153	// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
   154	//       of inst, it's ok to modify inst.Args here.
   155	func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
   156		// special cases for load/store instructions
   157		if _, ok := arg.(Offset); ok {
   158			if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
   159				panic(fmt.Errorf("wrong table: offset not followed by register"))
   160			}
   161		}
   162		switch arg := arg.(type) {
   163		case Reg:
   164			if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
   165				return "0"
   166			}
   167			if arg == R30 {
   168				return "g"
   169			}
   170			return strings.ToUpper(arg.String())
   171		case CondReg:
   172			// This op is left as its numerical value, not mapped onto CR + condition
   173			if inst.Op == ISEL {
   174				return fmt.Sprintf("$%d", (arg - Cond0LT))
   175			}
   176			if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
   177				return "" // don't show cr0 for cmp instructions
   178			} else if arg >= CR0 {
   179				return fmt.Sprintf("CR%d", int(arg-CR0))
   180			}
   181			bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
   182			if arg <= Cond0SO {
   183				return bit
   184			}
   185			return fmt.Sprintf("%s CR%d", bit, int(arg-Cond0LT)/4)
   186		case Imm:
   187			return fmt.Sprintf("$%d", arg)
   188		case SpReg:
   189			switch arg {
   190			case 8:
   191				return "LR"
   192			case 9:
   193				return "CTR"
   194			}
   195			return fmt.Sprintf("SPR(%d)", int(arg))
   196		case PCRel:
   197			addr := pc + uint64(int64(arg))
   198			if s, base := symname(addr); s != "" && base == addr {
   199				return fmt.Sprintf("%s(SB)", s)
   200			}
   201			return fmt.Sprintf("%#x", addr)
   202		case Label:
   203			return fmt.Sprintf("%#x", int(arg))
   204		case Offset:
   205			reg := inst.Args[argIndex+1].(Reg)
   206			removeArg(inst, argIndex+1)
   207			if reg == R0 {
   208				return fmt.Sprintf("%d(0)", int(arg))
   209			}
   210			return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
   211		}
   212		return fmt.Sprintf("???(%v)", arg)
   213	}
   214	
   215	// revCondMap maps a conditional register bit to its inverse, if possible.
   216	var revCondMap = map[string]string{
   217		"LT": "GE", "GT": "LE", "EQ": "NE",
   218	}
   219	
   220	// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
   221	var plan9OpMap = map[Op]string{
   222		LWARX: "LWAR",
   223		LDARX: "LDAR",
   224		LHARX: "LHAR",
   225		LBARX: "LBAR",
   226		ADDI:  "ADD",
   227		SRADI: "SRAD",
   228		SUBF:  "SUB",
   229		LI:    "MOVD",
   230		LBZ:   "MOVBZ", STB: "MOVB",
   231		LBZU: "MOVBZU", STBU: "MOVBU",
   232		LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
   233		LHZU: "MOVHZU", STHU: "MOVHU",
   234		LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
   235		LWZU: "MOVWZU", STWU: "MOVWU",
   236		LD: "MOVD", STD: "MOVD",
   237		LDU: "MOVDU", STDU: "MOVDU",
   238		CMPD: "CMP", CMPDI: "CMP",
   239		CMPW: "CMPW", CMPWI: "CMPW",
   240		CMPLD: "CMPU", CMPLDI: "CMPU",
   241		CMPLW: "CMPWU", CMPLWI: "CMPWU",
   242		MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
   243		B:  "BR",
   244		BL: "CALL",
   245	}
   246	

View as plain text