...

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

Documentation: cmd/vendor/golang.org/x/arch/ppc64/ppc64asm

     1  // Copyright 2014 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  	"bytes"
     9  	"fmt"
    10  	"strings"
    11  )
    12  
    13  var (
    14  	// bit 3 of index is a negated check.
    15  	condBit = [8]string{
    16  		"lt", "gt", "eq", "so",
    17  		"ge", "le", "ne", "ns"}
    18  )
    19  
    20  // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
    21  // This form typically matches the syntax defined in the Power ISA Reference Manual.
    22  func GNUSyntax(inst Inst, pc uint64) string {
    23  	var buf bytes.Buffer
    24  	// When there are all 0s, identify them as the disassembler
    25  	// in binutils would.
    26  	if inst.Enc == 0 {
    27  		return ".long 0x0"
    28  	} else if inst.Op == 0 {
    29  		return "error: unknown instruction"
    30  	}
    31  
    32  	PC := pc
    33  	// Special handling for some ops
    34  	startArg := 0
    35  	sep := " "
    36  	opName := inst.Op.String()
    37  	argList := inst.Args[:]
    38  
    39  	switch opName {
    40  	case "bc", "bcl", "bca", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
    41  		sfx := inst.Op.String()[2:]
    42  		bo := int(inst.Args[0].(Imm))
    43  		bi := inst.Args[1].(CondReg)
    44  		atsfx := [4]string{"", "?", "-", "+"}
    45  		decsfx := [2]string{"dnz", "dz"}
    46  
    47  		//BO field is... complicated (z == ignored bit, at == prediction hint)
    48  		//Paraphrased from ISA 3.1 Book I Section 2.4:
    49  		//
    50  		//0000z -> decrement ctr, b if ctr != 0 and CRbi == 0
    51  		//0001z -> decrement ctr, b if ctr == 0 and CRbi == 0
    52  		//001at -> b if CRbi == 0
    53  		//0100z -> decrement ctr, b if ctr != 0 and CRbi == 1
    54  		//0101z -> decrement ctr, b if ctr == 0 and CRbi == 1
    55  		//011at -> b if CRbi == 1
    56  		//1a00t -> decrement ctr, b if ctr != 0
    57  		//1a01t -> decrement ctr, b if ctr == 0
    58  		//1z1zz -> b always
    59  
    60  		// Decoding (in this order) we get
    61  		// BO & 0b00100 == 0b00000 -> dz if BO[1], else dnz (not simplified for bcctrl forms)
    62  		// BO & 0b10000 == 0b10000 -> (bc and bca forms not simplified), at = B[4]B[0] if B[2] != 0, done
    63  		// BO & 0b10000 == 0b00000 -> t if BO[3], else f
    64  		// BO & 0b10100 == 0b00100 -> at = B[0:1]
    65  
    66  		// BI fields rename as follows:
    67  		// less than            : lt BI%4==0 && test == t
    68  		// less than or equal   : le BI%4==1 && test == f
    69  		// equal 		: eq BI%4==2 && test == t
    70  		// greater than or equal: ge BI%4==0 && test == f
    71  		// greater than		: gt BI%4==1 && test == t
    72  		// not less than	: nl BI%4==0 && test == f
    73  		// not equal		: ne BI%4==2 && test == f
    74  		// not greater than	: ng BI%4==1 && test == f
    75  		// summary overflow	: so BI%4==3 && test == t
    76  		// not summary overflow : ns BI%4==3 && test == f
    77  		// unordered		: un BI%4==3 && test == t
    78  		// not unordered	: nu BI%4==3 && test == f
    79  		//
    80  		// Note, there are only 8 possible tests, but quite a few more
    81  		// ways to name fields.  For simplicity, we choose those in condBit.
    82  
    83  		at := 0   // 0 == no hint, 1 == reserved, 2 == not likely, 3 == likely
    84  		form := 1 // 1 == n/a,  0 == cr bit not set, 4 == cr bit set
    85  		cr := (bi - Cond0LT) / 4
    86  		bh := -1 // Only for lr/tar/ctr variants.
    87  		switch opName {
    88  		case "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
    89  			bh = int(inst.Args[2].(Imm))
    90  		}
    91  
    92  		if bo&0x14 == 0x14 {
    93  			if bo == 0x14 && bi == Cond0LT { // preferred form of unconditional branch
    94  				// Likewise, avoid printing fake b/ba/bl/bla
    95  				if opName != "bc" && opName != "bca" && opName != "bcl" && opName != "bcla" {
    96  					startArg = 2
    97  				}
    98  			}
    99  		} else if bo&0x04 == 0 { // ctr is decremented
   100  			if opName != "bcctr" && opName != "bcctrl" {
   101  				startArg = 1
   102  				tf := ""
   103  				if bo&0x10 == 0x00 {
   104  					tf = "f"
   105  					if bo&0x08 == 0x08 {
   106  						tf = "t"
   107  					}
   108  				}
   109  				sfx = decsfx[(bo>>1)&1] + tf + sfx
   110  			}
   111  			if bo&0x10 == 0x10 {
   112  				if opName != "bcctr" && opName != "bcctrl" {
   113  					startArg = 2
   114  				}
   115  				if bi != Cond0LT {
   116  					// A non-zero BI bit was encoded, but ignored by BO
   117  					startArg = 0
   118  				}
   119  				at = ((bo & 0x8) >> 2) | (bo & 0x1)
   120  			} else if bo&0x4 == 0x4 {
   121  				at = bo & 0x3
   122  			}
   123  		} else if bo&0x10 == 0x10 { // BI field is not used
   124  			if opName != "bca" && opName != "bc" {
   125  				at = ((bo & 0x8) >> 2) | (bo & 0x1)
   126  				startArg = 2
   127  			}
   128  			// If BI is encoded as a bit other than 0, no mnemonic.
   129  			if bo&0x14 == 0x14 {
   130  				startArg = 0
   131  			}
   132  		} else {
   133  			form = (bo & 0x8) >> 1
   134  			startArg = 2
   135  			if bo&0x14 == 0x04 {
   136  				at = bo & 0x3
   137  			}
   138  		}
   139  		sfx += atsfx[at]
   140  
   141  		if form != 1 {
   142  			bit := int((bi-Cond0LT)%4) | (^form)&0x4
   143  			sfx = condBit[bit] + sfx
   144  		}
   145  
   146  		if at != 1 && startArg > 0 && bh <= 0 {
   147  			str := fmt.Sprintf("b%s", sfx)
   148  			if startArg > 1 && (cr != 0 || bh > 0) {
   149  				str += fmt.Sprintf(" cr%d", cr)
   150  				sep = ","
   151  			}
   152  			buf.WriteString(str)
   153  			if startArg < 2 && bh == 0 {
   154  				str := fmt.Sprintf(" %s",
   155  					gnuArg(&inst, 1, inst.Args[1], PC))
   156  				buf.WriteString(str)
   157  				startArg = 3
   158  			} else if bh == 0 {
   159  				startArg = 3
   160  			}
   161  		} else {
   162  			if startArg == 0 || bh > 0 || at == 1 {
   163  				buf.WriteString(inst.Op.String())
   164  				buf.WriteString(atsfx[at])
   165  				startArg = 0
   166  			} else {
   167  				buf.WriteString("b" + sfx)
   168  			}
   169  			if bh == 0 {
   170  				str := fmt.Sprintf(" %d,%s", bo, gnuArg(&inst, 1, inst.Args[1], PC))
   171  				buf.WriteString(str)
   172  				startArg = 3
   173  			}
   174  		}
   175  
   176  	case "mtspr":
   177  		opcode := inst.Op.String()
   178  		buf.WriteString(opcode[0:2])
   179  		switch spr := inst.Args[0].(type) {
   180  		case SpReg:
   181  			switch spr {
   182  			case 1:
   183  				buf.WriteString("xer")
   184  				startArg = 1
   185  			case 8:
   186  				buf.WriteString("lr")
   187  				startArg = 1
   188  			case 9:
   189  				buf.WriteString("ctr")
   190  				startArg = 1
   191  			default:
   192  				buf.WriteString("spr")
   193  			}
   194  		default:
   195  			buf.WriteString("spr")
   196  		}
   197  
   198  	case "mfspr":
   199  		opcode := inst.Op.String()
   200  		buf.WriteString(opcode[0:2])
   201  		arg := inst.Args[0]
   202  		switch spr := inst.Args[1].(type) {
   203  		case SpReg:
   204  			switch spr {
   205  			case 1:
   206  				buf.WriteString("xer ")
   207  				buf.WriteString(gnuArg(&inst, 0, arg, PC))
   208  				startArg = 2
   209  			case 8:
   210  				buf.WriteString("lr ")
   211  				buf.WriteString(gnuArg(&inst, 0, arg, PC))
   212  				startArg = 2
   213  			case 9:
   214  				buf.WriteString("ctr ")
   215  				buf.WriteString(gnuArg(&inst, 0, arg, PC))
   216  				startArg = 2
   217  			case 268:
   218  				buf.WriteString("tb ")
   219  				buf.WriteString(gnuArg(&inst, 0, arg, PC))
   220  				startArg = 2
   221  			default:
   222  				buf.WriteString("spr")
   223  			}
   224  		default:
   225  			buf.WriteString("spr")
   226  		}
   227  
   228  	case "mtfsfi", "mtfsfi.":
   229  		buf.WriteString(opName)
   230  		l := inst.Args[2].(Imm)
   231  		if l == 0 {
   232  			// L == 0 is an extended mnemonic for the same.
   233  			asm := fmt.Sprintf(" %s,%s",
   234  				gnuArg(&inst, 0, inst.Args[0], PC),
   235  				gnuArg(&inst, 1, inst.Args[1], PC))
   236  			buf.WriteString(asm)
   237  			startArg = 3
   238  		}
   239  
   240  	case "paste.":
   241  		buf.WriteString(opName)
   242  		l := inst.Args[2].(Imm)
   243  		if l == 1 {
   244  			// L == 1 is an extended mnemonic for the same.
   245  			asm := fmt.Sprintf(" %s,%s",
   246  				gnuArg(&inst, 0, inst.Args[0], PC),
   247  				gnuArg(&inst, 1, inst.Args[1], PC))
   248  			buf.WriteString(asm)
   249  			startArg = 3
   250  		}
   251  
   252  	case "mtfsf", "mtfsf.":
   253  		buf.WriteString(opName)
   254  		l := inst.Args[3].(Imm)
   255  		if l == 0 {
   256  			// L == 0 is an extended mnemonic for the same.
   257  			asm := fmt.Sprintf(" %s,%s,%s",
   258  				gnuArg(&inst, 0, inst.Args[0], PC),
   259  				gnuArg(&inst, 1, inst.Args[1], PC),
   260  				gnuArg(&inst, 2, inst.Args[2], PC))
   261  			buf.WriteString(asm)
   262  			startArg = 4
   263  		}
   264  
   265  	case "sync":
   266  		lsc := inst.Args[0].(Imm)<<4 | inst.Args[1].(Imm)
   267  		switch lsc {
   268  		case 0x00:
   269  			buf.WriteString("hwsync")
   270  			startArg = 2
   271  		case 0x10:
   272  			buf.WriteString("lwsync")
   273  			startArg = 2
   274  		default:
   275  			buf.WriteString(opName)
   276  		}
   277  
   278  	case "lbarx", "lharx", "lwarx", "ldarx":
   279  		// If EH == 0, omit printing EH.
   280  		eh := inst.Args[3].(Imm)
   281  		if eh == 0 {
   282  			argList = inst.Args[:3]
   283  		}
   284  		buf.WriteString(inst.Op.String())
   285  
   286  	case "paddi":
   287  		// There are several extended mnemonics.  Notably, "pla" is
   288  		// the only valid mnemonic for paddi (R=1), In this case, RA must
   289  		// always be 0.  Otherwise it is invalid.
   290  		r := inst.Args[3].(Imm)
   291  		ra := inst.Args[1].(Reg)
   292  		str := opName
   293  		if ra == R0 {
   294  			name := []string{"pli", "pla"}
   295  			str = fmt.Sprintf("%s %s,%s",
   296  				name[r&1],
   297  				gnuArg(&inst, 0, inst.Args[0], PC),
   298  				gnuArg(&inst, 2, inst.Args[2], PC))
   299  			startArg = 4
   300  		} else {
   301  			str = fmt.Sprintf("%s %s,%s,%s", opName,
   302  				gnuArg(&inst, 0, inst.Args[0], PC),
   303  				gnuArg(&inst, 1, inst.Args[1], PC),
   304  				gnuArg(&inst, 2, inst.Args[2], PC))
   305  			startArg = 4
   306  			if r == 1 {
   307  				// This is an illegal encoding (ra != 0 && r == 1) on ISA 3.1.
   308  				v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
   309  				return fmt.Sprintf(".quad 0x%x", v)
   310  			}
   311  		}
   312  		buf.WriteString(str)
   313  
   314  	default:
   315  		// Prefixed load/stores do not print the displacement register when R==1 (they are PCrel).
   316  		// This also implies RA should be 0.  Likewise, when R==0, printing of R can be omitted.
   317  		if strings.HasPrefix(opName, "pl") || strings.HasPrefix(opName, "pst") {
   318  			r := inst.Args[3].(Imm)
   319  			ra := inst.Args[2].(Reg)
   320  			d := inst.Args[1].(Offset)
   321  			if r == 1 && ra == R0 {
   322  				str := fmt.Sprintf("%s %s,%d", opName, gnuArg(&inst, 0, inst.Args[0], PC), d)
   323  				buf.WriteString(str)
   324  				startArg = 4
   325  			} else {
   326  				str := fmt.Sprintf("%s %s,%d(%s)", opName,
   327  					gnuArg(&inst, 0, inst.Args[0], PC),
   328  					d,
   329  					gnuArg(&inst, 2, inst.Args[2], PC))
   330  				if r == 1 {
   331  					// This is an invalid encoding (ra != 0 && r == 1) on ISA 3.1.
   332  					v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
   333  					return fmt.Sprintf(".quad 0x%x", v)
   334  				}
   335  				buf.WriteString(str)
   336  				startArg = 4
   337  			}
   338  		} else {
   339  			buf.WriteString(opName)
   340  		}
   341  	}
   342  	for i, arg := range argList {
   343  		if arg == nil {
   344  			break
   345  		}
   346  		if i < startArg {
   347  			continue
   348  		}
   349  		text := gnuArg(&inst, i, arg, PC)
   350  		if text == "" {
   351  			continue
   352  		}
   353  		buf.WriteString(sep)
   354  		sep = ","
   355  		buf.WriteString(text)
   356  	}
   357  	return buf.String()
   358  }
   359  
   360  // gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules.
   361  // NOTE: because GNUSyntax is the only caller of this func, and it receives a copy
   362  // of inst, it's ok to modify inst.Args here.
   363  func gnuArg(inst *Inst, argIndex int, arg Arg, pc uint64) string {
   364  	// special cases for load/store instructions
   365  	if _, ok := arg.(Offset); ok {
   366  		if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
   367  			panic(fmt.Errorf("wrong table: offset not followed by register"))
   368  		}
   369  	}
   370  	switch arg := arg.(type) {
   371  	case Reg:
   372  		if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
   373  			return "0"
   374  		}
   375  		return arg.String()
   376  	case CondReg:
   377  		// The CondReg can either be found in a CMP, where the
   378  		// condition register field is being set, or in an instruction
   379  		// like a branch or isel that is testing a bit in a condition
   380  		// register field.
   381  		if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
   382  			return "" // don't show cr0 for cmp instructions
   383  		} else if arg >= CR0 {
   384  			return fmt.Sprintf("cr%d", int(arg-CR0))
   385  		}
   386  		bit := condBit[(arg-Cond0LT)%4]
   387  		if arg <= Cond0SO {
   388  			return bit
   389  		}
   390  		return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
   391  	case Imm:
   392  		return fmt.Sprintf("%d", arg)
   393  	case SpReg:
   394  		switch int(arg) {
   395  		case 1:
   396  			return "xer"
   397  		case 8:
   398  			return "lr"
   399  		case 9:
   400  			return "ctr"
   401  		case 268:
   402  			return "tb"
   403  		default:
   404  			return fmt.Sprintf("%d", int(arg))
   405  		}
   406  	case PCRel:
   407  		// If the arg is 0, use the relative address format.
   408  		// Otherwise the pc is meaningful, use absolute address.
   409  		if int(arg) == 0 {
   410  			return fmt.Sprintf(".%+#x", int(arg))
   411  		}
   412  		addr := pc + uint64(int64(arg))
   413  		return fmt.Sprintf("%#x", addr)
   414  	case Label:
   415  		return fmt.Sprintf("%#x", uint32(arg))
   416  	case Offset:
   417  		reg := inst.Args[argIndex+1].(Reg)
   418  		removeArg(inst, argIndex+1)
   419  		if reg == R0 {
   420  			return fmt.Sprintf("%d(0)", int(arg))
   421  		}
   422  		return fmt.Sprintf("%d(r%d)", int(arg), reg-R0)
   423  	}
   424  	return fmt.Sprintf("???(%v)", arg)
   425  }
   426  
   427  // removeArg removes the arg in inst.Args[index].
   428  func removeArg(inst *Inst, index int) {
   429  	for i := index; i < len(inst.Args); i++ {
   430  		if i+1 < len(inst.Args) {
   431  			inst.Args[i] = inst.Args[i+1]
   432  		} else {
   433  			inst.Args[i] = nil
   434  		}
   435  	}
   436  }
   437  
   438  // isLoadStoreOp returns true if op is a load or store instruction
   439  func isLoadStoreOp(op Op) bool {
   440  	switch op {
   441  	case LBZ, LBZU, LBZX, LBZUX:
   442  		return true
   443  	case LHZ, LHZU, LHZX, LHZUX:
   444  		return true
   445  	case LHA, LHAU, LHAX, LHAUX:
   446  		return true
   447  	case LWZ, LWZU, LWZX, LWZUX:
   448  		return true
   449  	case LWA, LWAX, LWAUX:
   450  		return true
   451  	case LD, LDU, LDX, LDUX:
   452  		return true
   453  	case LQ:
   454  		return true
   455  	case STB, STBU, STBX, STBUX:
   456  		return true
   457  	case STH, STHU, STHX, STHUX:
   458  		return true
   459  	case STW, STWU, STWX, STWUX:
   460  		return true
   461  	case STD, STDU, STDX, STDUX:
   462  		return true
   463  	case STQ:
   464  		return true
   465  	case LHBRX, LWBRX, STHBRX, STWBRX:
   466  		return true
   467  	case LBARX, LWARX, LHARX, LDARX:
   468  		return true
   469  	}
   470  	return false
   471  }
   472  

View as plain text