summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go')
-rw-r--r--vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go b/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
new file mode 100644
index 00000000..57a761e3
--- /dev/null
+++ b/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
@@ -0,0 +1,172 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "fmt"
+ "strings"
+)
+
+// GoSyntax returns the Go assembler syntax for the instruction.
+// The pc is the program counter of the first instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. It returns the name and base address of the symbol
+// containing the target, if any; otherwise it returns "", 0.
+func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+ if symname == nil {
+ symname = func(uint64) (string, uint64) { return "", 0 }
+ }
+ if inst.Op == 0 {
+ return "?"
+ }
+ var args []string
+ for i, a := range inst.Args[:] {
+ if a == nil {
+ break
+ }
+ if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
+ args = append(args, s)
+ }
+ }
+ var op string
+ op = plan9OpMap[inst.Op]
+ if op == "" {
+ op = strings.ToUpper(inst.Op.String())
+ }
+ // laid out the instruction
+ switch inst.Op {
+ default: // dst, sA, sB, ...
+ if len(args) == 0 {
+ return op
+ } else if len(args) == 1 {
+ return fmt.Sprintf("%s %s", op, args[0])
+ }
+ args = append(args, args[0])
+ return op + " " + strings.Join(args[1:], ", ")
+ // store instructions always have the memory operand at the end, no need to reorder
+ case STB, STBU, STBX, STBUX,
+ STH, STHU, STHX, STHUX,
+ STW, STWU, STWX, STWUX,
+ STD, STDU, STDX, STDUX,
+ STQ,
+ STHBRX, STWBRX:
+ return op + " " + strings.Join(args, ", ")
+ // branch instructions needs additional handling
+ case BCLR:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "RET"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BC:
+ if int(inst.Args[0].(Imm))&0x1c == 12 { // jump on cond bit set
+ return fmt.Sprintf("B%s %s", args[1], args[2])
+ } else if int(inst.Args[0].(Imm))&0x1c == 4 && revCondMap[args[1]] != "" { // jump on cond bit not set
+ return fmt.Sprintf("B%s %s", revCondMap[args[1]], args[2])
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCCTR:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "BR (CTR)"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCCTRL:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "BL (CTR)"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
+ return op + " " + strings.Join(args, ", ")
+ }
+}
+
+// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
+// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
+// of inst, it's ok to modify inst.Args here.
+func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
+ // special cases for load/store instructions
+ if _, ok := arg.(Offset); ok {
+ if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
+ panic(fmt.Errorf("wrong table: offset not followed by register"))
+ }
+ }
+ switch arg := arg.(type) {
+ case Reg:
+ if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
+ return "0"
+ }
+ if arg == R30 {
+ return "g"
+ }
+ return strings.ToUpper(arg.String())
+ case CondReg:
+ if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
+ return "" // don't show cr0 for cmp instructions
+ } else if arg >= CR0 {
+ return fmt.Sprintf("CR%d", int(arg-CR0))
+ }
+ bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
+ if arg <= Cond0SO {
+ return bit
+ }
+ return fmt.Sprintf("4*CR%d+%s", int(arg-Cond0LT)/4, bit)
+ case Imm:
+ return fmt.Sprintf("$%d", arg)
+ case SpReg:
+ switch arg {
+ case 8:
+ return "LR"
+ case 9:
+ return "CTR"
+ }
+ return fmt.Sprintf("SPR(%d)", int(arg))
+ case PCRel:
+ addr := pc + uint64(int64(arg))
+ if s, base := symname(addr); s != "" && base == addr {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ return fmt.Sprintf("%#x", addr)
+ case Label:
+ return fmt.Sprintf("%#x", int(arg))
+ case Offset:
+ reg := inst.Args[argIndex+1].(Reg)
+ removeArg(inst, argIndex+1)
+ if reg == R0 {
+ return fmt.Sprintf("%d(0)", int(arg))
+ }
+ return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
+ }
+ return fmt.Sprintf("???(%v)", arg)
+}
+
+// revCondMap maps a conditional register bit to its inverse, if possible.
+var revCondMap = map[string]string{
+ "LT": "GE", "GT": "LE", "EQ": "NE",
+}
+
+// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
+var plan9OpMap = map[Op]string{
+ LWARX: "LWAR", STWCX_: "STWCCC",
+ LDARX: "LDAR", STDCX_: "STDCCC",
+ LHARX: "LHAR", STHCX_: "STHCCC",
+ LBARX: "LBAR", STBCX_: "STBCCC",
+ ADDI: "ADD",
+ ADD_: "ADDCC",
+ LBZ: "MOVBZ", STB: "MOVB",
+ LBZU: "MOVBZU", STBU: "MOVBU", // TODO(minux): indexed forms are not handled
+ LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
+ LHZU: "MOVHZU", STHU: "MOVHU",
+ LI: "MOVD",
+ LIS: "ADDIS",
+ LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
+ LWZU: "MOVWZU", STWU: "MOVWU",
+ LD: "MOVD", STD: "MOVD",
+ LDU: "MOVDU", STDU: "MOVDU",
+ MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
+ B: "BR",
+ BL: "CALL",
+ CMPLD: "CMPU", CMPLW: "CMPWU",
+ CMPD: "CMP", CMPW: "CMPW",
+}