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