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 5package ppc64asm 6 7import ( 8 "bytes" 9 "fmt" 10 "strings" 11) 12 13// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. 14// This form typically matches the syntax defined in the Power ISA Reference Manual. 15func GNUSyntax(inst Inst) string { 16 var buf bytes.Buffer 17 if inst.Op == 0 { 18 return "error: unkown instruction" 19 } 20 buf.WriteString(inst.Op.String()) 21 sep := " " 22 for i, arg := range inst.Args[:] { 23 if arg == nil { 24 break 25 } 26 text := gnuArg(&inst, i, arg) 27 if text == "" { 28 continue 29 } 30 buf.WriteString(sep) 31 sep = "," 32 buf.WriteString(text) 33 } 34 return buf.String() 35} 36 37// gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules. 38// NOTE: because GNUSyntax is the only caller of this func, and it receives a copy 39// of inst, it's ok to modify inst.Args here. 40func gnuArg(inst *Inst, argIndex int, arg Arg) string { 41 // special cases for load/store instructions 42 if _, ok := arg.(Offset); ok { 43 if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil { 44 panic(fmt.Errorf("wrong table: offset not followed by register")) 45 } 46 } 47 switch arg := arg.(type) { 48 case Reg: 49 if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 { 50 return "0" 51 } 52 return arg.String() 53 case CondReg: 54 if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") { 55 return "" // don't show cr0 for cmp instructions 56 } else if arg >= CR0 { 57 return fmt.Sprintf("cr%d", int(arg-CR0)) 58 } 59 bit := [4]string{"lt", "gt", "eq", "so"}[(arg-Cond0LT)%4] 60 if arg <= Cond0SO { 61 return bit 62 } 63 return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit) 64 case Imm: 65 return fmt.Sprintf("%d", arg) 66 case SpReg: 67 return fmt.Sprintf("%d", int(arg)) 68 case PCRel: 69 return fmt.Sprintf(".%+#x", int(arg)) 70 case Label: 71 return fmt.Sprintf("%#x", uint32(arg)) 72 case Offset: 73 reg := inst.Args[argIndex+1].(Reg) 74 removeArg(inst, argIndex+1) 75 if reg == R0 { 76 return fmt.Sprintf("%d(0)", int(arg)) 77 } 78 return fmt.Sprintf("%d(r%d)", int(arg), reg-R0) 79 } 80 return fmt.Sprintf("???(%v)", arg) 81} 82 83// removeArg removes the arg in inst.Args[index]. 84func removeArg(inst *Inst, index int) { 85 for i := index; i < len(inst.Args); i++ { 86 if i+1 < len(inst.Args) { 87 inst.Args[i] = inst.Args[i+1] 88 } else { 89 inst.Args[i] = nil 90 } 91 } 92} 93 94// isLoadStoreOp returns true if op is a load or store instruction 95func isLoadStoreOp(op Op) bool { 96 switch op { 97 case LBZ, LBZU, LBZX, LBZUX: 98 return true 99 case LHZ, LHZU, LHZX, LHZUX: 100 return true 101 case LHA, LHAU, LHAX, LHAUX: 102 return true 103 case LWZ, LWZU, LWZX, LWZUX: 104 return true 105 case LWA, LWAX, LWAUX: 106 return true 107 case LD, LDU, LDX, LDUX: 108 return true 109 case LQ: 110 return true 111 case STB, STBU, STBX, STBUX: 112 return true 113 case STH, STHU, STHX, STHUX: 114 return true 115 case STW, STWU, STWX, STWUX: 116 return true 117 case STD, STDU, STDX, STDUX: 118 return true 119 case STQ: 120 return true 121 case LHBRX, LWBRX, STHBRX, STWBRX: 122 return true 123 } 124 return false 125} 126