github.com/bir3/gocompiler@v0.3.205/src/xvendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go (about) 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 }